2026-03-06 04:55:42 +00:00
<!DOCTYPE html>
< html lang = "en" >
< head >
< meta charset = "UTF-8" />
< meta name = "viewport" content = "width=device-width, initial-scale=1.0" />
< title > FabDash — Fabrication Project Dashboard</ title >
< link rel = "icon" href = "/logo.png" />
< link rel = "preconnect" href = "https://fonts.googleapis.com" />
< link href = "https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;900&display=swap" rel = "stylesheet" />
< style >
*, * :: before , * :: after { box-sizing : border-box ; margin : 0 ; padding : 0 ; }
: root {
--gold : #C9A84C ;
--gold-light : #E8C96A ;
--gold-muted : #8A6E2F ;
--bg : #111111 ;
--raised : #1A1A1A ;
--elevated : #242424 ;
--border : #2E2E2E ;
--text : #F5F5F5 ;
--muted : #888888 ;
--blue : #0EA5E9 ;
--amber : #F59E0B ;
--green : #22C55E ;
--red : #EF4444 ;
}
html { scroll-behavior : smooth ; }
body {
font-family : 'Inter' , system-ui , sans-serif ;
background : var ( -- bg );
color : var ( -- text );
overflow-x : hidden ;
}
/* ── Scrollbar ── */
:: -webkit-scrollbar { width : 6 px ; }
:: -webkit-scrollbar-track { background : var ( -- raised ); }
:: -webkit-scrollbar-thumb { background : var ( -- border ); border-radius : 3 px ; }
:: -webkit-scrollbar-thumb : hover { background : var ( -- gold - muted ); }
/* ── Nav ── */
nav {
position : fixed ;
top : 0 ; left : 0 ; right : 0 ;
z-index : 100 ;
display : flex ;
align-items : center ;
justify-content : space-between ;
padding : 0 2.5 rem ;
height : 64 px ;
background : rgba ( 17 , 17 , 17 , 0.88 );
backdrop-filter : blur ( 12 px );
border-bottom : 1 px solid var ( -- border );
}
. nav-brand {
display : flex ;
align-items : center ;
gap : 10 px ;
text-decoration : none ;
}
. nav-brand img {
width : 32 px ; height : 32 px ;
object-fit : contain ;
}
. nav-brand span {
font-size : 1.1 rem ;
font-weight : 900 ;
letter-spacing : 0.12 em ;
color : var ( -- gold );
}
. nav-cta {
display : inline-flex ;
align-items : center ;
gap : 6 px ;
background : var ( -- gold );
color : #000 ;
font-weight : 700 ;
font-size : 0.82 rem ;
letter-spacing : 0.05 em ;
padding : 8 px 20 px ;
border-radius : 4 px ;
text-decoration : none ;
transition : background 0.2 s ;
}
. nav-cta : hover { background : var ( -- gold - light ); }
/* ── Hero ── */
. hero {
min-height : 100 vh ;
display : flex ;
flex-direction : column ;
align-items : center ;
justify-content : center ;
text-align : center ;
padding : 100 px 2 rem 4 rem ;
position : relative ;
overflow : hidden ;
}
. hero-bg {
position : absolute ;
inset : 0 ;
background :
radial-gradient ( ellipse 80 % 60 % at 50 % 0 % , rgba ( 201 , 168 , 76 , 0.10 ) 0 % , transparent 70 % ),
radial-gradient ( ellipse 50 % 40 % at 80 % 80 % , rgba ( 201 , 168 , 76 , 0.06 ) 0 % , transparent 60 % );
pointer-events : none ;
}
/* parallax grid */
. hero-grid {
position : absolute ;
inset : 0 ;
background-image :
linear-gradient ( rgba ( 201 , 168 , 76 , 0.04 ) 1 px , transparent 1 px ),
linear-gradient ( 90 deg , rgba ( 201 , 168 , 76 , 0.04 ) 1 px , transparent 1 px );
background-size : 60 px 60 px ;
pointer-events : none ;
transform : translateZ ( 0 );
}
. hero-logo {
width : 100 px ; height : 100 px ;
object-fit : contain ;
margin-bottom : 1.5 rem ;
filter : drop-shadow ( 0 0 24 px rgba ( 201 , 168 , 76 , 0.5 ));
animation : float 4 s ease-in-out infinite ;
}
@ keyframes float {
0 %, 100 % { transform : translateY ( 0 ); }
50 % { transform : translateY ( -10 px ); }
}
. hero-eyebrow {
font-size : 0.72 rem ;
font-weight : 700 ;
letter-spacing : 0.2 em ;
color : var ( -- gold );
text-transform : uppercase ;
margin-bottom : 1 rem ;
}
. hero-title {
font-size : clamp ( 2.6 rem , 6 vw , 4.8 rem );
font-weight : 900 ;
line-height : 1.05 ;
letter-spacing : -0.02 em ;
max-width : 820 px ;
margin : 0 auto 1.25 rem ;
}
. hero-title em {
font-style : normal ;
color : var ( -- gold );
}
. hero-sub {
font-size : clamp ( 1 rem , 2 vw , 1.2 rem );
color : var ( -- muted );
max-width : 560 px ;
margin : 0 auto 2.5 rem ;
line-height : 1.65 ;
}
. hero-actions {
display : flex ;
gap : 1 rem ;
align-items : center ;
justify-content : center ;
flex-wrap : wrap ;
}
. btn-primary {
display : inline-flex ;
align-items : center ;
gap : 8 px ;
background : var ( -- gold );
color : #000 ;
font-weight : 700 ;
font-size : 0.9 rem ;
letter-spacing : 0.04 em ;
padding : 12 px 28 px ;
border-radius : 4 px ;
text-decoration : none ;
transition : background 0.2 s , box-shadow 0.2 s ;
}
. btn-primary : hover {
background : var ( -- gold - light );
box-shadow : 0 0 20 px rgba ( 201 , 168 , 76 , 0.4 );
}
. btn-ghost {
display : inline-flex ;
align-items : center ;
gap : 8 px ;
background : transparent ;
color : var ( -- text );
font-weight : 600 ;
font-size : 0.9 rem ;
padding : 12 px 24 px ;
border : 1 px solid var ( -- border );
border-radius : 4 px ;
text-decoration : none ;
transition : border-color 0.2 s , color 0.2 s ;
}
. btn-ghost : hover { border-color : var ( -- gold ); color : var ( -- gold ); }
/* ── Section base ── */
section {
padding : 6 rem 2 rem ;
}
. container {
max-width : 1120 px ;
margin : 0 auto ;
}
. section-label {
font-size : 0.7 rem ;
font-weight : 700 ;
letter-spacing : 0.22 em ;
text-transform : uppercase ;
color : var ( -- gold );
margin-bottom : 0.75 rem ;
}
. section-title {
font-size : clamp ( 1.8 rem , 4 vw , 2.8 rem );
font-weight : 800 ;
letter-spacing : -0.02 em ;
line-height : 1.1 ;
margin-bottom : 1 rem ;
}
. section-sub {
color : var ( -- muted );
font-size : 1.05 rem ;
line-height : 1.65 ;
max-width : 560 px ;
}
/* ── Demo Preview ── */
. demo-section {
background : linear-gradient ( 180 deg , var ( -- bg ) 0 % , #0d0d0d 100 % );
}
. demo-shell {
background : var ( -- raised );
border : 1 px solid var ( -- border );
border-radius : 8 px ;
overflow : hidden ;
box-shadow : 0 24 px 80 px rgba ( 0 , 0 , 0 , 0.6 ), 0 0 0 1 px var ( -- border );
margin-top : 3 rem ;
}
/* Window chrome */
. demo-topbar {
display : flex ;
align-items : center ;
gap : 8 px ;
padding : 12 px 16 px ;
background : #0f0f0f ;
border-bottom : 1 px solid var ( -- border );
}
. dot { width : 10 px ; height : 10 px ; border-radius : 50 % ; }
. dot-r { background : #FF5F57 ; }
. dot-y { background : #FEBC2E ; }
. dot-g { background : #28C840 ; }
. demo-url {
flex : 1 ;
text-align : center ;
font-size : 0.72 rem ;
color : var ( -- muted );
}
/* App layout mock */
. app-mock {
display : flex ;
height : 520 px ;
}
/* Sidebar */
. mock-sidebar {
width : 200 px ;
flex-shrink : 0 ;
background : #0f0f0f ;
border-right : 1 px solid var ( -- border );
display : flex ;
flex-direction : column ;
padding : 14 px 0 ;
}
. sidebar-logo-row {
display : flex ;
align-items : center ;
gap : 8 px ;
padding : 0 14 px 14 px ;
border-bottom : 1 px solid var ( -- border );
margin-bottom : 14 px ;
}
. sidebar-logo-row img {
width : 24 px ; height : 24 px ; object-fit : contain ;
}
. sidebar-wordmark {
font-size : 0.7 rem ;
font-weight : 900 ;
letter-spacing : 0.14 em ;
color : var ( -- gold );
}
. sidebar-project {
padding : 0 10 px ;
margin-bottom : 4 px ;
}
. project-bar {
display : flex ;
align-items : center ;
gap : 8 px ;
padding : 7 px 8 px ;
border-radius : 4 px ;
background : var ( -- elevated );
cursor : pointer ;
}
. project-dot {
width : 8 px ; height : 8 px ;
border-radius : 50 % ;
flex-shrink : 0 ;
}
. project-name {
font-size : 0.72 rem ;
font-weight : 600 ;
color : var ( -- text );
white-space : nowrap ;
overflow : hidden ;
text-overflow : ellipsis ;
}
. project-count {
margin-left : auto ;
font-size : 0.62 rem ;
color : var ( -- muted );
background : var ( -- raised );
border-radius : 10 px ;
padding : 1 px 6 px ;
}
. deliverable-row {
display : flex ;
align-items : center ;
gap : 7 px ;
padding : 5 px 8 px 5 px 24 px ;
font-size : 0.67 rem ;
color : var ( -- muted );
}
. badge {
font-size : 0.58 rem ;
font-weight : 600 ;
padding : 1 px 5 px ;
border-radius : 3 px ;
white-space : nowrap ;
}
. badge-upcoming { background : rgba ( 14 , 165 , 233 , 0.18 ); color : #38BDF8 ; }
. badge-progress { background : rgba ( 245 , 158 , 11 , 0.18 ); color : #FCD34D ; }
. badge-complete { background : rgba ( 34 , 197 , 94 , 0.18 ); color : #4ADE80 ; }
. badge-overdue { background : rgba ( 239 , 68 , 68 , 0.18 ); color : #F87171 ; }
/* Main calendar mock */
. mock-main {
flex : 1 ;
display : flex ;
flex-direction : column ;
overflow : hidden ;
}
. cal-header {
display : flex ;
align-items : center ;
justify-content : space-between ;
padding : 12 px 18 px ;
border-bottom : 1 px solid var ( -- border );
background : var ( -- raised );
}
. cal-title {
font-size : 0.85 rem ;
font-weight : 700 ;
letter-spacing : 0.02 em ;
}
. cal-nav {
display : flex ;
gap : 6 px ;
}
. cal-btn {
background : var ( -- elevated );
border : 1 px solid var ( -- border );
border-radius : 4 px ;
color : var ( -- text );
font-size : 0.68 rem ;
font-weight : 600 ;
padding : 4 px 10 px ;
cursor : pointer ;
}
. cal-btn . active {
background : var ( -- gold );
color : #000 ;
border-color : var ( -- gold );
}
/* Calendar grid */
. cal-grid {
flex : 1 ;
display : flex ;
flex-direction : column ;
overflow : hidden ;
}
. cal-dow {
display : grid ;
grid-template-columns : repeat ( 7 , 1 fr );
border-bottom : 1 px solid var ( -- border );
}
. cal-dow-cell {
padding : 6 px ;
text-align : center ;
font-size : 0.6 rem ;
font-weight : 700 ;
letter-spacing : 0.08 em ;
color : var ( -- muted );
text-transform : uppercase ;
}
. cal-weeks {
flex : 1 ;
display : flex ;
flex-direction : column ;
}
. cal-week {
flex : 1 ;
display : grid ;
grid-template-columns : repeat ( 7 , 1 fr );
border-bottom : 1 px solid var ( -- border );
}
. cal-week : last-child { border-bottom : none ; }
. cal-day {
border-right : 1 px solid var ( -- border );
padding : 4 px 5 px ;
min-height : 0 ;
overflow : hidden ;
}
. cal-day : last-child { border-right : none ; }
. cal-day . other-month . day-num { color : #444 ; }
. cal-day . today . day-num {
background : var ( -- gold );
color : #000 ;
border-radius : 50 % ;
width : 20 px ; height : 20 px ;
display : flex ; align-items : center ; justify-content : center ;
}
. day-num {
font-size : 0.6 rem ;
font-weight : 600 ;
color : var ( -- muted );
margin-bottom : 3 px ;
width : 20 px ; height : 20 px ;
display : flex ; align-items : center ; justify-content : center ;
}
. cal-event {
font-size : 0.55 rem ;
font-weight : 600 ;
padding : 2 px 5 px ;
border-radius : 2 px ;
margin-bottom : 2 px ;
white-space : nowrap ;
overflow : hidden ;
text-overflow : ellipsis ;
color : #000 ;
}
/* ── Benefits ── */
. benefits-section {
background : linear-gradient ( 180 deg , #0d0d0d 0 % , var ( -- bg ) 100 % );
}
. benefits-grid {
display : grid ;
grid-template-columns : repeat ( auto - fit , minmax ( 300 px , 1 fr ));
gap : 1.5 rem ;
margin-top : 3 rem ;
}
. benefit-card {
background : var ( -- raised );
border : 1 px solid var ( -- border );
border-radius : 6 px ;
padding : 1.75 rem ;
position : relative ;
overflow : hidden ;
transition : border-color 0.25 s , transform 0.25 s ;
}
. benefit-card :: before {
content : '' ;
position : absolute ;
top : 0 ; left : 0 ; right : 0 ;
height : 2 px ;
background : linear-gradient ( 90 deg , var ( -- gold ), var ( -- gold - muted ));
opacity : 0 ;
transition : opacity 0.25 s ;
}
. benefit-card : hover {
border-color : var ( -- gold - muted );
transform : translateY ( -3 px );
}
. benefit-card : hover :: before { opacity : 1 ; }
. benefit-icon {
font-size : 1.8 rem ;
margin-bottom : 1 rem ;
line-height : 1 ;
}
. benefit-title {
font-size : 1 rem ;
font-weight : 700 ;
margin-bottom : 0.5 rem ;
}
. benefit-desc {
font-size : 0.875 rem ;
color : var ( -- muted );
line-height : 1.65 ;
}
/* ── Heatmap Demo ── */
. heatmap-section {
background : var ( -- bg );
}
. heatmap-wrap {
margin-top : 3 rem ;
background : var ( -- raised );
border : 1 px solid var ( -- border );
border-radius : 6 px ;
padding : 1.5 rem ;
}
. heatmap-header {
display : flex ;
align-items : center ;
justify-content : space-between ;
margin-bottom : 1 rem ;
}
. heatmap-title {
font-size : 0.8 rem ;
font-weight : 700 ;
letter-spacing : 0.06 em ;
text-transform : uppercase ;
color : var ( -- gold );
}
. heatmap-stats {
display : flex ;
gap : 1.5 rem ;
}
. heatmap-stat { text-align : right ; }
. heatmap-stat-val {
font-size : 1.1 rem ;
font-weight : 800 ;
color : var ( -- gold );
}
. heatmap-stat-lbl {
font-size : 0.62 rem ;
color : var ( -- muted );
text-transform : uppercase ;
letter-spacing : 0.1 em ;
}
. heatmap-weeks {
display : flex ;
gap : 4 px ;
overflow-x : auto ;
padding-bottom : 4 px ;
}
. heatmap-week {
display : flex ;
flex-direction : column ;
gap : 3 px ;
flex-shrink : 0 ;
}
. heatmap-week-label {
font-size : 0.55 rem ;
color : var ( -- muted );
text-align : center ;
height : 14 px ;
line-height : 14 px ;
}
. heatmap-cell {
width : 28 px ; height : 28 px ;
border-radius : 3 px ;
display : flex ;
align-items : center ;
justify-content : center ;
font-size : 0.58 rem ;
font-weight : 700 ;
color : #000 ;
}
. heatmap-cell . d0 { background : var ( -- elevated ); color : var ( -- muted ); }
. heatmap-cell . d1 { background : rgba ( 201 , 168 , 76 , 0.20 ); color : var ( -- gold ); }
. heatmap-cell . d2 { background : rgba ( 201 , 168 , 76 , 0.40 ); color : var ( -- gold - light ); }
. heatmap-cell . d3 { background : rgba ( 201 , 168 , 76 , 0.65 ); color : #1a1200 ; }
. heatmap-cell . d4 { background : var ( -- gold ); }
. heatmap-cell . d5 { background : var ( -- gold - light ); }
/* ── Features ── */
. features-section {
background : linear-gradient ( 180 deg , var ( -- bg ) 0 % , #0d0d0d 100 % );
}
. features-grid {
display : grid ;
grid-template-columns : 1 fr 1 fr ;
gap : 4 rem ;
align-items : center ;
margin-top : 3 rem ;
}
@ media ( max-width : 768px ) {
. features-grid { grid-template-columns : 1 fr ; gap : 2 rem ; }
. app-mock { height : 420 px ; }
. mock-sidebar { width : 140 px ; }
nav { padding : 0 1 rem ; }
}
. feature-list {
list-style : none ;
display : flex ;
flex-direction : column ;
gap : 1.2 rem ;
}
. feature-item {
display : flex ;
gap : 1 rem ;
align-items : flex-start ;
}
. feature-icon-wrap {
width : 36 px ; height : 36 px ;
border-radius : 6 px ;
background : rgba ( 201 , 168 , 76 , 0.1 );
border : 1 px solid rgba ( 201 , 168 , 76 , 0.2 );
display : flex ; align-items : center ; justify-content : center ;
flex-shrink : 0 ;
font-size : 1 rem ;
}
. feature-text h4 {
font-size : 0.9 rem ;
font-weight : 700 ;
margin-bottom : 0.25 rem ;
}
. feature-text p {
font-size : 0.82 rem ;
color : var ( -- muted );
line-height : 1.6 ;
}
/* Focus drawer mock */
. focus-mock {
background : var ( -- raised );
border : 1 px solid var ( -- border );
border-radius : 6 px ;
overflow : hidden ;
}
. focus-header {
padding : 12 px 16 px ;
border-bottom : 1 px solid var ( -- border );
display : flex ;
align-items : center ;
justify-content : space-between ;
}
. focus-header-title {
font-size : 0.8 rem ;
font-weight : 700 ;
}
. focus-project-dot {
width : 8 px ; height : 8 px ;
border-radius : 50 % ;
display : inline-block ;
margin-right : 6 px ;
}
. focus-timeline {
display : flex ;
gap : 0 ;
padding : 1.5 rem 1 rem ;
overflow-x : auto ;
}
. timeline-item {
display : flex ;
flex-direction : column ;
align-items : center ;
gap : 8 px ;
min-width : 110 px ;
}
. timeline-card {
background : var ( -- elevated );
border : 1 px solid var ( -- border );
border-radius : 4 px ;
padding : 8 px 10 px ;
width : 100 % ;
text-align : center ;
}
. timeline-card . active {
border-color : var ( -- gold );
box-shadow : 0 0 10 px rgba ( 201 , 168 , 76 , 0.25 );
}
. timeline-card-title {
font-size : 0.67 rem ;
font-weight : 600 ;
color : var ( -- text );
margin-bottom : 4 px ;
}
. timeline-card-date {
font-size : 0.58 rem ;
color : var ( -- muted );
}
. timeline-line {
display : flex ;
align-items : center ;
width : 100 % ;
position : relative ;
}
. timeline-dot {
width : 8 px ; height : 8 px ;
border-radius : 50 % ;
background : var ( -- gold );
flex-shrink : 0 ;
position : relative ;
z-index : 1 ;
}
. timeline-connector {
flex : 1 ;
height : 1 px ;
background : var ( -- border );
}
. timeline-item : last-child . timeline-connector { display : none ; }
/* ── How It Works ── */
. how-section {
background : #0d0d0d ;
}
. steps-grid {
display : grid ;
grid-template-columns : repeat ( auto - fit , minmax ( 220 px , 1 fr ));
gap : 2 rem ;
margin-top : 3 rem ;
counter-reset : steps ;
}
. step-card {
position : relative ;
padding-left : 0 ;
}
. step-num {
font-size : 3 rem ;
font-weight : 900 ;
color : rgba ( 201 , 168 , 76 , 0.12 );
line-height : 1 ;
margin-bottom : 0.75 rem ;
font-variant-numeric : tabular-nums ;
}
. step-title {
font-size : 1 rem ;
font-weight : 700 ;
margin-bottom : 0.5 rem ;
}
. step-desc {
font-size : 0.875 rem ;
color : var ( -- muted );
line-height : 1.65 ;
}
/* ── Docker CTA ── */
. docker-section {
background : var ( -- bg );
}
. docker-box {
background : var ( -- raised );
border : 1 px solid var ( -- border );
border-radius : 8 px ;
padding : 2 rem 2 rem 1.5 rem ;
margin-top : 2 rem ;
}
. docker-box-label {
font-size : 0.65 rem ;
font-weight : 700 ;
letter-spacing : 0.16 em ;
text-transform : uppercase ;
color : var ( -- muted );
margin-bottom : 0.75 rem ;
}
. code-block {
background : #0a0a0a ;
border : 1 px solid var ( -- border );
border-radius : 4 px ;
padding : 1 rem 1.25 rem ;
font-family : 'JetBrains Mono' , 'Fira Code' , 'Courier New' , monospace ;
font-size : 0.8 rem ;
color : var ( -- text );
overflow-x : auto ;
margin-bottom : 1 rem ;
white-space : pre ;
line-height : 1.7 ;
}
. code-block . c-comment { color : var ( -- muted ); }
. code-block . c-gold { color : var ( -- gold ); }
. code-block . c-green { color : #4ADE80 ; }
. code-block . c-blue { color : #60A5FA ; }
/* ── Footer ── */
footer {
background : #0a0a0a ;
border-top : 1 px solid var ( -- border );
padding : 2.5 rem 2 rem ;
text-align : center ;
}
. footer-brand {
display : flex ;
align-items : center ;
justify-content : center ;
gap : 8 px ;
margin-bottom : 0.75 rem ;
}
. footer-brand img {
width : 24 px ; height : 24 px ; object-fit : contain ;
}
. footer-brand span {
font-size : 0.85 rem ;
font-weight : 900 ;
letter-spacing : 0.14 em ;
color : var ( -- gold );
}
. footer-note {
font-size : 0.78 rem ;
color : var ( -- muted );
}
. gold-divider {
width : 60 px ;
height : 2 px ;
background : linear-gradient ( 90 deg , transparent , var ( -- gold ), transparent );
margin : 2 rem auto ;
}
/* ── Parallax scroll effect ── */
. parallax-layer {
will-change : transform ;
}
</ style >
</ head >
< body >
<!-- Navigation -->
< nav >
< a class = "nav-brand" href = "#" >
< img src = "/logo.png" alt = "FabDash logo" onerror = "this.style.display='none'" />
< span > FABDASH</ span >
</ a >
< a class = "nav-cta" href = "/" > Open App → </ a >
</ nav >
<!-- ══════════════════════════════════════════
HERO
══════════════════════════════════════════ -->
< section class = "hero" >
< div class = "hero-bg" ></ div >
< div class = "hero-grid parallax-layer" data-speed = "0.3" ></ div >
< img src = "/logo.png" class = "hero-logo" alt = "FabDash logo"
onerror = "this.style.display='none'" />
< p class = "hero-eyebrow" > Fabrication Project Dashboard</ p >
< h1 class = "hero-title" >
Track every cut, weld,< br /> and deadline — < em > visually</ em >
</ h1 >
< p class = "hero-sub" >
FabDash is a self-hosted calendar dashboard built for fabrication shops.
Drag, drop, and deliver on time — no spreadsheet gymnastics required.
</ p >
< div class = "hero-actions" >
< a href = "/" class = "btn-primary" > Open Dashboard → </ a >
< a href = "#demo" class = "btn-ghost" > See Demo ↓ </ a >
</ div >
</ section >
<!-- ══════════════════════════════════════════
DEMO PREVIEW
══════════════════════════════════════════ -->
< section class = "demo-section" id = "demo" >
< div class = "container" >
< p class = "section-label" > Live Demo</ p >
< h2 class = "section-title" > Your shop, at a glance</ h2 >
< p class = "section-sub" >
Every active project, every deliverable, color-coded and laid out on an
interactive calendar — exactly as it looks inside FabDash.
</ p >
< div class = "demo-shell" >
<!-- Window chrome -->
< div class = "demo-topbar" >
< span class = "dot dot-r" ></ span >
< span class = "dot dot-y" ></ span >
< span class = "dot dot-g" ></ span >
< span class = "demo-url" > fabdash.local:8080</ span >
</ div >
<!-- App layout -->
< div class = "app-mock" >
<!-- Sidebar -->
< div class = "mock-sidebar" >
< div class = "sidebar-logo-row" >
< img src = "/logo.png" alt = "" onerror = "this.style.display='none'" />
< span class = "sidebar-wordmark" > FABDASH</ span >
</ div >
<!-- Project: Tucson -->
< div class = "sidebar-project" >
< div class = "project-bar" >
< span class = "project-dot" style = "background:#E67E22" ></ span >
< span class = "project-name" > Tucson</ span >
< span class = "project-count" > 4</ span >
</ div >
< div class = "deliverable-row" >
< span style = "flex:1;font-size:0.64rem;overflow:hidden;text-overflow:ellipsis;white-space:nowrap" > Cut Extrusion</ span >
< span class = "badge badge-progress" > Active</ span >
</ div >
< div class = "deliverable-row" >
< span style = "flex:1;font-size:0.64rem;overflow:hidden;text-overflow:ellipsis;white-space:nowrap" > Fabricate Assembly</ span >
< span class = "badge badge-upcoming" > Soon</ span >
</ div >
</ div >
<!-- Project: Mesa -->
< div class = "sidebar-project" >
< div class = "project-bar" >
< span class = "project-dot" style = "background:#3B82F6" ></ span >
< span class = "project-name" > Mesa</ span >
< span class = "project-count" > 3</ span >
</ div >
< div class = "deliverable-row" >
< span style = "flex:1;font-size:0.64rem;overflow:hidden;text-overflow:ellipsis;white-space:nowrap" > Weld Subframe</ span >
< span class = "badge badge-complete" > Done</ span >
</ div >
< div class = "deliverable-row" >
< span style = "flex:1;font-size:0.64rem;overflow:hidden;text-overflow:ellipsis;white-space:nowrap" > Paint & Finish</ span >
< span class = "badge badge-progress" > Active</ span >
</ div >
</ div >
<!-- Project: Phoenix Shelter -->
< div class = "sidebar-project" >
< div class = "project-bar" >
< span class = "project-dot" style = "background:#8B5CF6" ></ span >
< span class = "project-name" > Phoenix Shelter</ span >
< span class = "project-count" > 5</ span >
</ div >
< div class = "deliverable-row" >
< span style = "flex:1;font-size:0.64rem;overflow:hidden;text-overflow:ellipsis;white-space:nowrap" > Roof Panel Cuts</ span >
< span class = "badge badge-overdue" > Late</ span >
</ div >
</ div >
<!-- Project: Scottsdale -->
< div class = "sidebar-project" >
< div class = "project-bar" >
< span class = "project-dot" style = "background:#10B981" ></ span >
< span class = "project-name" > Scottsdale</ span >
< span class = "project-count" > 2</ span >
</ div >
</ div >
</ div >
<!-- Calendar -->
< div class = "mock-main" >
< div class = "cal-header" >
< span class = "cal-title" > March 2026</ span >
< div class = "cal-nav" >
< button class = "cal-btn" > ← </ button >
< button class = "cal-btn active" > Month</ button >
< button class = "cal-btn" > Week</ button >
< button class = "cal-btn" > Today</ button >
< button class = "cal-btn" > → </ button >
</ div >
</ div >
< div class = "cal-grid" >
< div class = "cal-dow" >
< div class = "cal-dow-cell" > Sun</ div >
< div class = "cal-dow-cell" > Mon</ div >
< div class = "cal-dow-cell" > Tue</ div >
< div class = "cal-dow-cell" > Wed</ div >
< div class = "cal-dow-cell" > Thu</ div >
< div class = "cal-dow-cell" > Fri</ div >
< div class = "cal-dow-cell" > Sat</ div >
</ div >
< div class = "cal-weeks" >
<!-- Week 1 (Mar 1 → Mar 7) — note: Mar 1 is Sunday 2026 -->
< div class = "cal-week" >
< div class = "cal-day" >< div class = "day-num" > 1</ div ></ div >
< div class = "cal-day" >< div class = "day-num" > 2</ div >
< div class = "cal-event" style = "background:#E67E22" > Cut Extrusion</ div >
</ div >
< div class = "cal-day" >< div class = "day-num" > 3</ div ></ div >
< div class = "cal-day" >< div class = "day-num" > 4</ div >
< div class = "cal-event" style = "background:#3B82F6" > Weld Subframe</ div >
</ div >
< div class = "cal-day" >< div class = "day-num" > 5</ div >
< div class = "cal-event" style = "background:#8B5CF6" > Roof Cuts</ div >
</ div >
< div class = "cal-day" >< div class = "day-num" > 6</ div >
< div class = "cal-event" style = "background:#10B981" > Scottsdale</ div >
</ div >
< div class = "cal-day" >< div class = "day-num" > 7</ div ></ div >
</ div >
<!-- Week 2 -->
< div class = "cal-week" >
< div class = "cal-day" >< div class = "day-num" > 8</ div ></ div >
< div class = "cal-day" >< div class = "day-num" > 9</ div >
< div class = "cal-event" style = "background:#E67E22" > Fab Assembly</ div >
</ div >
< div class = "cal-day today" >< div class = "day-num" > 10</ div >
< div class = "cal-event" style = "background:#3B82F6" > Paint & Finish</ div >
</ div >
< div class = "cal-day" >< div class = "day-num" > 11</ div ></ div >
< div class = "cal-day" >< div class = "day-num" > 12</ div >
< div class = "cal-event" style = "background:#8B5CF6" > Panel Weld</ div >
</ div >
< div class = "cal-day" >< div class = "day-num" > 13</ div >
< div class = "cal-event" style = "background:#E67E22" > QC Check</ div >
</ div >
< div class = "cal-day" >< div class = "day-num" > 14</ div ></ div >
</ div >
<!-- Week 3 -->
< div class = "cal-week" >
< div class = "cal-day" >< div class = "day-num" > 15</ div ></ div >
< div class = "cal-day" >< div class = "day-num" > 16</ div >
< div class = "cal-event" style = "background:#10B981" > Install Prep</ div >
</ div >
< div class = "cal-day" >< div class = "day-num" > 17</ div ></ div >
< div class = "cal-day" >< div class = "day-num" > 18</ div >
< div class = "cal-event" style = "background:#E67E22" > Powder Coat</ div >
</ div >
< div class = "cal-day" >< div class = "day-num" > 19</ div >
< div class = "cal-event" style = "background:#3B82F6" > Final QC</ div >
</ div >
< div class = "cal-day" >< div class = "day-num" > 20</ div ></ div >
< div class = "cal-day" >< div class = "day-num" > 21</ div ></ div >
</ div >
<!-- Week 4 -->
< div class = "cal-week" >
< div class = "cal-day" >< div class = "day-num" > 22</ div >
< div class = "cal-event" style = "background:#8B5CF6" > Glass Mount</ div >
</ div >
< div class = "cal-day" >< div class = "day-num" > 23</ div ></ div >
< div class = "cal-day" >< div class = "day-num" > 24</ div >
< div class = "cal-event" style = "background:#E67E22" > Ship TUC-01</ div >
</ div >
< div class = "cal-day" >< div class = "day-num" > 25</ div ></ div >
< div class = "cal-day" >< div class = "day-num" > 26</ div >
< div class = "cal-event" style = "background:#10B981" > Delivery</ div >
</ div >
< div class = "cal-day" >< div class = "day-num" > 27</ div ></ div >
< div class = "cal-day" >< div class = "day-num" > 28</ div ></ div >
</ div >
<!-- Week 5 -->
< div class = "cal-week" >
< div class = "cal-day" >< div class = "day-num" > 29</ div ></ div >
< div class = "cal-day" >< div class = "day-num" > 30</ div >
< div class = "cal-event" style = "background:#3B82F6" > MSA Closeout</ div >
</ div >
< div class = "cal-day" >< div class = "day-num" > 31</ div ></ div >
< div class = "cal-day other-month" >< div class = "day-num" > 1</ div ></ div >
< div class = "cal-day other-month" >< div class = "day-num" > 2</ div ></ div >
< div class = "cal-day other-month" >< div class = "day-num" > 3</ div ></ div >
< div class = "cal-day other-month" >< div class = "day-num" > 4</ div ></ div >
</ div >
</ div >
</ div >
</ div >
</ div >
</ div >
</ div >
</ section >
<!-- ══════════════════════════════════════════
BENEFITS
══════════════════════════════════════════ -->
< section class = "benefits-section" id = "benefits" >
< div class = "container" >
< p class = "section-label" > Why FabDash</ p >
< h2 class = "section-title" > Built for the shop floor,< br /> not the boardroom</ h2 >
< p class = "section-sub" >
Spreadsheets break. Sticky notes fall. FabDash keeps every project visible
and every deadline accountable — in your browser, on your server.
</ p >
< div class = "benefits-grid" >
< div class = "benefit-card" >
< div class = "benefit-icon" > 🗓️</ div >
< h3 class = "benefit-title" > Drag-and-drop calendar</ h3 >
< p class = "benefit-desc" >
Reschedule deliverables by dragging events between days. Month, week,
and day views let you zoom in when deadlines stack up.
</ p >
</ div >
< div class = "benefit-card" >
< div class = "benefit-icon" > 🎨</ div >
< h3 class = "benefit-title" > Color-coded projects</ h3 >
< p class = "benefit-desc" >
Assign a distinct color to each job. At a glance you know which events
belong to which project — no key required.
</ p >
</ div >
< div class = "benefit-card" >
< div class = "benefit-icon" > 🌡️</ div >
< h3 class = "benefit-title" > Workload heatmap</ h3 >
< p class = "benefit-desc" >
A 20-week density grid reveals crunch periods before they sneak up on
your crew. Spot hot weeks and redistribute the load.
</ p >
</ div >
< div class = "benefit-card" >
< div class = "benefit-icon" > ⚡</ div >
< h3 class = "benefit-title" > Instant status tracking</ h3 >
< p class = "benefit-desc" >
Upcoming, In Progress, Completed, and Overdue statuses are
auto-computed and color-coded so nothing slips through the cracks.
</ p >
</ div >
< div class = "benefit-card" >
< div class = "benefit-icon" > 🔄</ div >
< h3 class = "benefit-title" > Undo any action</ h3 >
< p class = "benefit-desc" >
Deleted a deliverable by accident? A 30-second countdown toast lets you
reverse any change before it's permanent.
</ p >
</ div >
< div class = "benefit-card" >
< div class = "benefit-icon" > 🔒</ div >
< h3 class = "benefit-title" > 100% self-hosted</ h3 >
< p class = "benefit-desc" >
Your project data never leaves your network. Deploy with a single Docker
command and own everything — database and all.
</ p >
</ div >
</ div >
</ div >
</ section >
<!-- ══════════════════════════════════════════
HEATMAP DEMO
══════════════════════════════════════════ -->
< section class = "heatmap-section" >
< div class = "container" >
< p class = "section-label" > Workload Heatmap</ p >
< h2 class = "section-title" > See crunch before it hits</ h2 >
< p class = "section-sub" >
The 20-week heatmap shows deliverable density across your entire pipeline.
Gold-hot cells flag overloaded weeks so you can rebalance while there's
still time.
</ p >
< div class = "heatmap-wrap" >
< div class = "heatmap-header" >
< span class = "heatmap-title" > 20-Week Workload — March → July 2026</ span >
< div class = "heatmap-stats" >
< div class = "heatmap-stat" >
< div class = "heatmap-stat-val" > 18</ div >
< div class = "heatmap-stat-lbl" > Active</ div >
</ div >
< div class = "heatmap-stat" >
< div class = "heatmap-stat-val" > 4</ div >
< div class = "heatmap-stat-lbl" > Projects</ div >
</ div >
< div class = "heatmap-stat" >
< div class = "heatmap-stat-val" > 3</ div >
< div class = "heatmap-stat-lbl" > Overdue</ div >
</ div >
</ div >
</ div >
< div class = "heatmap-weeks" id = "heatmap" ></ div >
</ div >
</ div >
</ section >
<!-- ══════════════════════════════════════════
FEATURE DETAILS (Focus View)
══════════════════════════════════════════ -->
< section class = "features-section" id = "features" >
< div class = "container" >
< div class = "features-grid" >
<!-- Focus timeline mock -->
< div class = "focus-mock" >
< div class = "focus-header" >
< span class = "focus-header-title" >
< span class = "focus-project-dot" style = "background:#E67E22" ></ span >
Tucson — Focus View
</ span >
< span class = "badge badge-progress" > 4 deliverables</ span >
</ div >
< div class = "focus-timeline" >
< div class = "timeline-item" >
< div class = "timeline-card" >
< div class = "timeline-card-title" > Cut Extrusion</ div >
< div class = "timeline-card-date" > Mar 2</ div >
< div style = "margin-top:4px" >< span class = "badge badge-complete" > Done</ span ></ div >
</ div >
< div class = "timeline-line" >
< div class = "timeline-dot" style = "background:#22C55E" ></ div >
< div class = "timeline-connector" ></ div >
</ div >
</ div >
< div class = "timeline-item" >
< div class = "timeline-card active" >
< div class = "timeline-card-title" > Fab Assembly</ div >
< div class = "timeline-card-date" > Mar 9</ div >
< div style = "margin-top:4px" >< span class = "badge badge-progress" > Active</ span ></ div >
</ div >
< div class = "timeline-line" >
< div class = "timeline-dot" style = "background:#F59E0B" ></ div >
< div class = "timeline-connector" ></ div >
</ div >
</ div >
< div class = "timeline-item" >
< div class = "timeline-card" >
< div class = "timeline-card-title" > QC Check</ div >
< div class = "timeline-card-date" > Mar 13</ div >
< div style = "margin-top:4px" >< span class = "badge badge-upcoming" > Soon</ span ></ div >
</ div >
< div class = "timeline-line" >
< div class = "timeline-dot" style = "background:#0EA5E9" ></ div >
< div class = "timeline-connector" ></ div >
</ div >
</ div >
< div class = "timeline-item" >
< div class = "timeline-card" >
< div class = "timeline-card-title" > Ship TUC-01</ div >
< div class = "timeline-card-date" > Mar 24</ div >
< div style = "margin-top:4px" >< span class = "badge badge-upcoming" > Soon</ span ></ div >
</ div >
< div class = "timeline-line" >
< div class = "timeline-dot" ></ div >
< div class = "timeline-connector" ></ div >
</ div >
</ div >
</ div >
</ div >
<!-- Feature list -->
< div >
< p class = "section-label" > Focus View</ p >
< h2 class = "section-title" > Zoom in on one project</ h2 >
< p class = "section-sub" style = "margin-bottom:1.75rem" >
Click any project to slide up a horizontal timeline showing every
deliverable in order. Edit, drag, and update status without leaving
the view.
</ p >
< ul class = "feature-list" >
< li class = "feature-item" >
< div class = "feature-icon-wrap" > 🖱️</ div >
< div class = "feature-text" >
< h4 > Double-click to edit</ h4 >
< p > Double-click any deliverable card to open an inline editor — change the title, date, or status in one step.</ p >
</ div >
</ li >
< li class = "feature-item" >
< div class = "feature-icon-wrap" > ⌨️</ div >
< div class = "feature-text" >
< h4 > Keyboard shortcuts</ h4 >
< p > N to create, B to toggle the sidebar, ← → to navigate months, T to jump to today, Esc to close modals.</ p >
</ div >
</ li >
< li class = "feature-item" >
< div class = "feature-icon-wrap" > 📁</ div >
< div class = "feature-text" >
< h4 > Google Drive link</ h4 >
< p > Attach a Drive folder to each project so every drawing, spec sheet, and photo lives one click away.</ p >
</ div >
</ li >
< li class = "feature-item" >
< div class = "feature-icon-wrap" > 🖱️</ div >
< div class = "feature-text" >
< h4 > Right-click context menus</ h4 >
< p > Right-click any event or deliverable to edit, duplicate, change status, or delete — no menu diving.</ p >
</ div >
</ li >
</ ul >
</ div >
</ div >
</ div >
</ section >
<!-- ══════════════════════════════════════════
HOW IT WORKS
══════════════════════════════════════════ -->
< section class = "how-section" id = "how" >
< div class = "container" >
< p class = "section-label" > Getting Started</ p >
< h2 class = "section-title" > Up and running in minutes</ h2 >
< p class = "section-sub" >
One Docker command. No accounts, no SaaS subscriptions, no per-seat pricing.
Just your data on your hardware.
</ p >
< div class = "steps-grid" >
< div class = "step-card" >
< div class = "step-num" > 01</ div >
< h3 class = "step-title" > Pull the image</ h3 >
< p class = "step-desc" > Run < code style = "color:var(--gold)" > docker run</ code > with a volume mount for persistent storage. That's the entire installation.</ p >
</ div >
< div class = "step-card" >
< div class = "step-num" > 02</ div >
< h3 class = "step-title" > Create a project</ h3 >
< p class = "step-desc" > Hit < kbd style = "background:var(--elevated);border:1px solid var(--border);border-radius:3px;padding:1px 5px;font-size:0.8em" > N</ kbd > or click the + button. Name it, pick a color, add an optional Drive link.</ p >
</ div >
< div class = "step-card" >
< div class = "step-num" > 03</ div >
< h3 class = "step-title" > Add deliverables</ h3 >
< p class = "step-desc" > Each deliverable gets a title, a due date, and a status. They appear instantly on the calendar as color-coded events.</ p >
</ div >
< div class = "step-card" >
< div class = "step-num" > 04</ div >
< h3 class = "step-title" > Drag and deliver</ h3 >
< p class = "step-desc" > Reschedule by dragging events. Mark complete with a right-click. Watch the heatmap cool down as work ships.</ p >
</ div >
</ div >
</ div >
</ section >
<!-- ══════════════════════════════════════════
DOCKER CTA
══════════════════════════════════════════ -->
< section class = "docker-section" >
< div class = "container" style = "text-align:center" >
< p class = "section-label" > Self-Hosted</ p >
< h2 class = "section-title" > Deploy on your own hardware</ h2 >
< p class = "section-sub" style = "margin:1rem auto 0" >
FabDash ships as a single Docker container with an embedded SQLite database.
Works perfectly on Unraid, TrueNAS, a Raspberry Pi, or any Linux server.
</ p >
< div class = "docker-box" style = "max-width:680px;margin:2rem auto 0;text-align:left" >
< div class = "docker-box-label" > Quick Start</ div >
< div class = "code-block" >< span class = "c-comment" > # Pull and run FabDash</ span >
docker run -d \
--name fabdash \
-p < span class = "c-blue" > 8080</ span > :< span class = "c-blue" > 8080</ span > \
-v < span class = "c-green" > ./data</ span > :/app/data \
--restart unless-stopped \
fabdash:latest</ div >
< div class = "docker-box-label" style = "margin-top:1rem" > Then open</ div >
< div class = "code-block" >< span class = "c-gold" > http://your-server-ip:< span class = "c-blue" > 8080</ span ></ span ></ div >
</ div >
< div style = "margin-top:2.5rem" >
< a href = "/" class = "btn-primary" style = "font-size:1rem;padding:14px 36px" >
Open FabDash →
</ a >
</ div >
</ div >
</ section >
< div class = "gold-divider" ></ div >
<!-- ══════════════════════════════════════════
FOOTER
══════════════════════════════════════════ -->
< footer >
< div class = "footer-brand" >
< img src = "/logo.png" alt = "" onerror = "this.style.display='none'" />
< span > FABDASH</ span >
</ div >
< p class = "footer-note" > Self-hosted fabrication dashboard — your shop, your data.</ p >
2026-03-06 04:59:40 +00:00
< a href = "https://github.com/jasonMPM/fabdash" target = "_blank" rel = "noopener"
style = "display:inline-flex;align-items:center;gap:6px;margin-top:0.75rem;font-size:0.78rem;color:var(--muted);text-decoration:none;transition:color 0.2s"
onmouseover = "this.style.color='var(--gold)'" onmouseout = "this.style.color='var(--muted)'" >
< svg width = "15" height = "15" viewBox = "0 0 24 24" fill = "currentColor" aria-hidden = "true" >
< path d = "M12 0C5.37 0 0 5.37 0 12c0 5.31 3.435 9.795 8.205 11.385.6.105.825-.255.825-.57 0-.285-.015-1.23-.015-2.235-3.015.555-3.795-.735-4.035-1.41-.135-.345-.72-1.41-1.23-1.695-.42-.225-1.02-.78-.015-.795.945-.015 1.62.87 1.845 1.23 1.08 1.815 2.805 1.305 3.495.99.105-.78.42-1.305.765-1.605-2.67-.3-5.46-1.335-5.46-5.925 0-1.305.465-2.385 1.23-3.225-.12-.3-.54-1.53.12-3.18 0 0 1.005-.315 3.3 1.23.96-.27 1.98-.405 3-.405s2.04.135 3 .405c2.295-1.56 3.3-1.23 3.3-1.23.66 1.65.24 2.88.12 3.18.765.84 1.23 1.905 1.23 3.225 0 4.605-2.805 5.625-5.475 5.925.435.375.81 1.095.81 2.22 0 1.605-.015 2.895-.015 3.3 0 .315.225.69.825.57A12.02 12.02 0 0 0 24 12c0-6.63-5.37-12-12-12z" />
</ svg >
github.com/jasonMPM/fabdash
</ a >
2026-03-06 04:55:42 +00:00
</ footer >
<!-- ══════════════════════════════════════════
SCRIPTS
══════════════════════════════════════════ -->
< script >
/* ── Heatmap generator ── */
( function () {
const density = [ 0 , 1 , 0 , 2 , 3 , 1 , 0 , 2 , 4 , 5 , 3 , 2 , 1 , 0 , 2 , 3 , 4 , 2 , 1 , 0 ];
const labels = [
'Mar 1' , 'Mar 8' , 'Mar 15' , 'Mar 22' , 'Mar 29' ,
'Apr 5' , 'Apr 12' , 'Apr 19' , 'Apr 26' ,
'May 3' , 'May 10' , 'May 17' , 'May 24' , 'May 31' ,
'Jun 7' , 'Jun 14' , 'Jun 21' , 'Jun 28' ,
'Jul 5' , 'Jul 12'
];
const wrap = document . getElementById ( 'heatmap' );
density . forEach (( d , i ) => {
const col = document . createElement ( 'div' );
col . className = 'heatmap-week' ;
const lbl = document . createElement ( 'div' );
lbl . className = 'heatmap-week-label' ;
lbl . textContent = labels [ i ];
col . appendChild ( lbl );
for ( let row = 0 ; row < 5 ; row ++ ) {
const cell = document . createElement ( 'div' );
const v = Math . max ( 0 , Math . min ( 5 , d + Math . round (( Math . random () - 0.4 ) * 1.2 )));
cell . className = `heatmap-cell d ${ v } ` ;
cell . textContent = v || '' ;
col . appendChild ( cell );
}
wrap . appendChild ( col );
});
})();
/* ── Parallax on scroll ── */
( function () {
const layers = document . querySelectorAll ( '.parallax-layer' );
function onScroll () {
const y = window . scrollY ;
layers . forEach ( el => {
const speed = parseFloat ( el . dataset . speed || 0.2 );
el . style . transform = `translateY( ${ y * speed } px)` ;
});
}
window . addEventListener ( 'scroll' , onScroll , { passive : true });
})();
/* ── Scroll-reveal ── */
( function () {
const style = document . createElement ( 'style' );
style . textContent = `
.reveal { opacity: 0; transform: translateY(28px); transition: opacity 0.55s ease, transform 0.55s ease; }
.reveal.visible { opacity: 1; transform: none; }
` ;
document . head . appendChild ( style );
const targets = document . querySelectorAll (
'.benefit-card, .step-card, .feature-item, .focus-mock, .heatmap-wrap, .demo-shell, .docker-box'
);
targets . forEach (( el , i ) => {
el . classList . add ( 'reveal' );
el . style . transitionDelay = ` ${ ( i % 4 ) * 80 } ms` ;
});
const io = new IntersectionObserver ( entries => {
entries . forEach ( e => {
if ( e . isIntersecting ) { e . target . classList . add ( 'visible' ); io . unobserve ( e . target ); }
});
}, { threshold : 0.12 });
targets . forEach ( el => io . observe ( el ));
})();
</ script >
</ body >
</ html >