# Muddy Roots Festival Schedule: Squarespace 7.1 Build Guide
**Live reference (mirror this exactly):** https://muddyrootsworldwide.com/tennessee/schedule/
**Target:** a page at slug **`/tennessee/schedule`** on muddyroots.com.
**Match standard:** the rebuild must match the live reference pixel for pixel and function for function. Same tabs, same filters, same stars, same Save to Phone download.
This page is one self-contained app. Unlike the other pages, you do NOT rebuild it with Squarespace sections. It is two pastes: one into the page's header injection, one into a single Code Block. A Core plan or higher is required for code injection.
The schedule page keeps its own compact top bar and footer by design, so the injected code hides the native Squarespace header and footer on this page only.
---
## 1. Create the page
1. In **Pages**, click **+**, choose **Blank Page**. Name it `Festival Schedule`.
2. Open **Page Settings > General** and set the **URL Slug** to exactly: `tennessee/schedule`
(Squarespace accepts a slash in the slug. If your plan refuses it, use `festivalschedule` and tell the owner so links can be updated.)
3. Keep the page OUT of the site navigation. People reach it from the Tennessee page's Festival Schedule button and sub-nav link.
## 2. Page Settings: SEO and social
1. **Page Settings > SEO > SEO Title**, paste exactly:
`Festival Schedule 2026 | Muddy Roots Music Festival`
2. **SEO Description**, paste exactly:
`Muddy Roots 2026 Schedule: View full band set times for all 3 stages in Cookeville, TN, Sept 3-6. Star your favorite artists & save the lineup to your phone!`
3. **Social Image**: upload the same og.jpg used on the Tennessee page (asset manifest has the URL).
4. Make sure **Hide this page from search engine results** is UNCHECKED once the page is live and correct.
## 3. Paste one: Page Header Code Injection
Open **Page Settings > Advanced > Page Header Code Injection** and paste the entire block. It loads the two fonts, adds the structured data, hides the native header and footer on this page only, and carries all the page styling.
COPY SOURCE (use this, not the code printed below): open https://muddyguide.mybuildstudio.com/schedule-header.txt in a tab, Select All, Copy. It is the exact same code as the block below, served as plain text so nothing gets mangled. The block below is only for reading.
```
<!-- Muddy Roots Festival Schedule: page header injection. Paste ALL of this into
Page Settings > Advanced > Page Header Code Injection for the schedule page. -->
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Anton&family=Oswald:wght@400;500;600;700&display=swap" rel="stylesheet">
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@graph": [
{
"@type": "WebPage",
"@id": "https://www.muddyroots.com/tennessee/schedule#webpage",
"url": "https://www.muddyroots.com/tennessee/schedule",
"name": "Festival Schedule 2026 | Muddy Roots Music Festival",
"description": "Muddy Roots 2026 Schedule: View full band set times for all 3 stages in Cookeville, TN, Sept 3-6. Star your favorite artists & save the lineup to your phone!"
},
{
"@type": "BreadcrumbList",
"itemListElement": [
{ "@type": "ListItem", "position": 1, "name": "Muddy Roots Music Festival", "item": "https://www.muddyroots.com/tennessee" },
{ "@type": "ListItem", "position": 2, "name": "Festival Schedule", "item": "https://www.muddyroots.com/tennessee/schedule" }
]
}
]
}
</script>
<style>
/* Hide the native Squarespace header and footer on this page only, the schedule has its own */
#header, .header, .sqs-announcement-bar-dropzone,
#footer-sections, .sqs-footer, footer.sqs-layout { display:none !important; }
/* Kill Squarespace section padding around the code block so the schedule runs edge to edge */
#page .page-section { padding:0 !important; }
#page .content-wrapper { padding:0 !important; max-width:none !important; }
body { background:#0B0A08; }
body{margin:0;background:#0B0A08;color:#fff;font-family:Oswald,system-ui,sans-serif;-webkit-font-smoothing:antialiased}
a{color:#F5D34C;text-decoration:none}
a:hover{color:#E8391D}
button{font-family:Oswald,sans-serif}
input::placeholder{color:rgba(255,255,255,.45)}
@keyframes mrPulse{0%,100%{opacity:1}50%{opacity:.4}}
.topbar{display:flex;align-items:center;justify-content:space-between;gap:16px;padding:18px 22px;background:#000;border-bottom:1px solid #1d1a16}
.topbar .wordmark{font-family:Anton,sans-serif;font-size:22px;letter-spacing:.5px;color:#F5D34C;text-transform:uppercase}
a.wordmark:hover{color:#E8391D}
.topbar .right{display:flex;align-items:center;gap:18px}
.topbar .dates{font-size:13px;font-weight:600;letter-spacing:2px;color:#fff;text-transform:uppercase}
.topbar .badge{background:#E8391D;color:#fff;font-weight:700;font-size:13px;letter-spacing:2px;padding:9px 16px;border-radius:4px;text-transform:uppercase}
@media (max-width:560px){.topbar .dates{display:none}}
.hero{text-align:center;padding:52px 20px 34px;background:radial-gradient(ellipse at 50% 0%,#1a120c 0%,#0B0A08 70%)}
.hero .eyebrow{font-size:14px;font-weight:600;letter-spacing:4px;color:#E8391D;text-transform:uppercase;margin-bottom:12px}
.hero h1{font-family:Anton,sans-serif;font-size:clamp(44px,8vw,84px);line-height:.95;margin:0;color:#fff;text-transform:uppercase;font-weight:400}
.hero p{font-size:17px;font-weight:400;color:rgba(255,255,255,.75);max-width:520px;margin:18px auto 24px;line-height:1.5}
.savebtn{background:#E8391D;color:#fff;border:none;cursor:pointer;font-family:Anton,sans-serif;font-size:20px;letter-spacing:2px;text-transform:uppercase;padding:16px 34px;border-radius:4px}
.savebtn:hover{background:#c22c14}
.hero .hint{font-size:13px;color:rgba(255,255,255,.5);margin-top:12px}
.filters{position:sticky;top:0;z-index:20;background:#0B0A08;border-bottom:1px solid #1d1a16;padding:14px 16px 12px}
.filters .inner{max-width:760px;margin:0 auto;display:flex;flex-direction:column;gap:10px}
.searchwrap{display:flex;align-items:center;gap:12px;background:#161310;border:1px solid #2c261f;border-radius:999px;padding:4px 8px 4px 20px}
.searchwrap svg{flex:none}
.searchwrap input{flex:1;min-width:0;background:transparent;border:none;outline:none;color:#fff;font-family:Oswald,sans-serif;font-size:17px;font-weight:500;padding:12px 0;letter-spacing:.5px}
.clearbtn{flex:none;width:36px;height:36px;border-radius:50%;border:none;background:#2c261f;color:#fff;font-size:16px;cursor:pointer;display:none}
.daytabs{display:flex;gap:6px}
.daytab{flex:1;cursor:pointer;border-radius:6px;padding:8px 4px 7px;text-align:center;text-transform:uppercase;background:transparent}
.daytab .lbl{display:block;font-family:Anton,sans-serif;font-size:17px;letter-spacing:1px;font-weight:400}
.daytab .dt{display:block;font-size:11px;font-weight:600;letter-spacing:1.5px;opacity:.75}
.chiprow{display:flex;flex-wrap:wrap;gap:6px;align-items:center}
.chip{cursor:pointer;border-radius:999px;padding:7px 14px;font-size:13px;font-weight:600;letter-spacing:1px;text-transform:uppercase;background:transparent}
.chiprow .gap{flex:1}
main{max-width:760px;margin:0 auto;padding:10px 16px 40px}
.searchnote{font-size:13px;font-weight:600;letter-spacing:2px;color:rgba(255,255,255,.5);text-transform:uppercase;padding:16px 4px 0}
.dayhead{display:flex;align-items:baseline;justify-content:space-between;gap:12px;color:#0B0A08;padding:12px 16px;border-radius:4px;margin-bottom:4px}
.dayhead .dl{font-family:Anton,sans-serif;font-size:22px;letter-spacing:1px;text-transform:uppercase;font-weight:400}
.dayhead .dd{font-size:13px;font-weight:700;letter-spacing:2px}
.setrow{display:flex;align-items:center;gap:12px;padding:12px 8px;border-bottom:1px solid #1d1a16}
.setrow .time{width:76px;flex:none;font-weight:600;font-size:15px;color:rgba(255,255,255,.65);letter-spacing:.5px}
.setrow .mid{flex:1;min-width:0;display:flex;align-items:center;gap:10px;flex-wrap:wrap}
.setrow .band{font-family:Anton,sans-serif;font-size:19px;letter-spacing:.5px;color:#fff;text-transform:uppercase;font-weight:400}
.nowbadge{flex:none;font-size:11px;font-weight:700;letter-spacing:1.5px;color:#fff;background:#E8391D;border-radius:3px;padding:3px 8px;text-transform:uppercase;animation:mrPulse 1.6s ease-in-out infinite}
.nextbadge{flex:none;font-size:11px;font-weight:700;letter-spacing:1.5px;color:#F5D34C;border:1px solid #F5D34C;border-radius:3px;padding:2px 7px;text-transform:uppercase}
.tbdbadge{flex:none;font-size:11px;font-weight:700;letter-spacing:1.5px;color:#D7CEC1;border:1px solid #D7CEC1;border-radius:3px;padding:2px 7px;text-transform:uppercase}
.stagechip{flex:none;font-size:12px;font-weight:600;letter-spacing:1px;text-transform:uppercase;border-radius:999px;padding:3px 10px;border:1px solid}
.starbtn{flex:none;width:44px;height:44px;border:none;background:transparent;cursor:pointer;font-size:22px;line-height:1}
.actrow{padding:14px 8px;border-bottom:1px solid #1d1a16}
.act-name{font-family:Anton,sans-serif;font-size:19px;letter-spacing:.5px;color:#fff;text-transform:uppercase;font-weight:400}
.act-meta{font-size:13px;font-weight:600;color:rgba(255,255,255,.6);letter-spacing:1px;text-transform:uppercase;margin-top:4px}
.emptybox{text-align:center;padding:70px 20px;color:rgba(255,255,255,.55)}
.emptybox .big{font-family:Anton,sans-serif;font-size:28px;text-transform:uppercase;color:#fff;margin-bottom:8px;font-weight:400}
.emptybox .small{font-size:15px}
.savemodal{position:fixed;inset:0;z-index:50;background:rgba(0,0,0,.9);display:flex;flex-direction:column;align-items:center;justify-content:center;padding:20px;gap:14px}
.savemodal img{max-width:min(400px,84vw);max-height:52vh;object-fit:contain;border:1px solid #2c261f;border-radius:6px;background:#0B0A08}
.savemodal .t{font-family:Anton,sans-serif;font-size:22px;text-transform:uppercase;color:#fff;text-align:center;font-weight:400}
.savemodal .s{font-size:15px;color:rgba(255,255,255,.78);max-width:340px;text-align:center;line-height:1.5}
.savemodal .dl{background:#E8391D;color:#fff;font-family:Anton,sans-serif;font-size:17px;letter-spacing:1.5px;text-transform:uppercase;padding:12px 26px;border-radius:4px}
.savemodal .close{background:transparent;border:1px solid rgba(255,255,255,.3);color:#fff;border-radius:999px;padding:8px 22px;font-size:14px;cursor:pointer}
footer{text-align:center;padding:26px 20px 44px;border-top:1px solid #1d1a16;color:rgba(255,255,255,.45);font-size:13px;letter-spacing:1.5px;text-transform:uppercase;display:flex;flex-direction:column;gap:8px}
</style>
```
## 4. Paste two: the Code Block
1. Edit the page. Delete any starter blocks so the page is empty.
2. Add ONE **Code Block**. Set its type to **HTML** and turn **Display Source** OFF.
3. COPY SOURCE (use this, not the code printed below): open https://muddyguide.mybuildstudio.com/schedule-codeblock.txt in a tab, Select All, Copy. It is the exact same code as the block below, served as plain text so nothing gets mangled. The block below is only for reading.
4. Paste the copied text into the Code Block:
```
<!-- Muddy Roots Festival Schedule: page body. Paste ALL of this into ONE Code Block
(HTML mode, Display Source OFF) as the only content on the schedule page. -->
<header class="topbar">
<a class="wordmark" href="https://www.muddyroots.com/tennessee">Muddy Roots Worldwide</a>
<div class="right">
<div class="dates">Sept 3-6 · Cookeville, TN</div>
<div class="badge">2026 Schedule</div>
</div>
</header>
<section class="hero">
<div class="eyebrow">71+ Bands · Three Stages · Free Camping</div>
<h1>Festival Schedule</h1>
<p>Got your tickets?! Save the full schedule to your phone. No reception needed. Star your bands to build a personal set list you can save too.</p>
<button class="savebtn" id="saveBtn">⤓ Save to Phone</button>
<div class="hint" id="saveHint">Downloads a one-page PNG. Save it to your camera roll. No reception needed.</div>
</section>
<section class="filters">
<div class="inner">
<div class="searchwrap">
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="#F5D34C" stroke-width="2.4"><circle cx="10.5" cy="10.5" r="7"></circle><line x1="15.8" y1="15.8" x2="21" y2="21"></line></svg>
<input id="search" placeholder="Search by day, time, stage, or band" autocomplete="off">
<button class="clearbtn" id="clearBtn" aria-label="Clear search">✕</button>
</div>
<div class="daytabs" id="dayTabs"></div>
<div class="chiprow" id="chipRow"></div>
</div>
</section>
<main>
<div class="searchnote" id="searchNote" style="display:none">Search results across all days</div>
<div id="list"></div>
<div class="emptybox" id="emptyBox" style="display:none">
<div class="big">No sets found</div>
<div class="small" id="emptyHint"></div>
</div>
</main>
<footer>
<div>Free Camping · Free Showers · All times Central · Set times subject to change</div>
<div><a href="https://www.muddyroots.com/tennessee">muddyroots.com/tennessee</a></div>
</footer>
<script>
(function(){
'use strict';
var ACCENT = '#E8391D';
var STAGES = {
WOOD: { name: 'Wood Stage', color: '#E8B84B', dur: 60 },
LITTLE: { name: 'Little Tent', color: '#F07A38', dur: 45 },
BIG: { name: 'Big Tent', color: '#E0301E', dur: 60 },
KICKIT: { name: 'Kick It Tent', color: '#F5D34C', dur: 60 },
CAMP: { name: 'Not in Tent', color: '#D7CEC1', dur: 60 }
};
/* Times are minutes from midnight on the festival day (1440+ = after midnight). */
var DAYS = [
{ key:'THU', label:'Thursday', tab:'THURS', date:'Sept 3', iso:'2026-09-03', color:'#F5D34C', sets:[
[1020,'LITTLE','Sarah Slade & The Slow Burn'],[1080,'WOOD','Strayhound'],[1140,'LITTLE','Matt Pless'],
[1200,'WOOD','James Leg'],[1260,'LITTLE','Joe Buck Yourself'],[1320,'WOOD','Jimmy "Duck" Holmes'],
[1380,'CAMP','Campfire Jam','info']
]},
{ key:'FRI', label:'Friday', tab:'FRI', date:'Sept 4', iso:'2026-09-04', color:'#F0A03C', sets:[
[540,'BIG','Yoga'],[540,'KICKIT','Storytime with Rebekah'],[600,'KICKIT','Scrapbook Class with Maddie'],[660,'BIG','Bootprint'],[690,'LITTLE','Horse Breakfast'],[720,'WOOD','Gremlins'],[720,'KICKIT','Poetry Workshop with Emily'],
[780,'BIG','Uncle Skunkle'],[810,'LITTLE','Ramblin Ricky Tate'],[840,'WOOD','Total Flesh'],
[900,'BIG','American Dream Survivors'],[930,'LITTLE','Shrudd'],[960,'WOOD','Dead Runes'],
[1020,'BIG','Yosemite in Black'],[1050,'LITTLE','Belly Hole Freak'],[1080,'WOOD','Jason Dea West'],
[1140,'BIG','The Monsters'],[1170,'LITTLE','S.A.I.G.O.N'],[1200,'WOOD','Squid Pisser'],
[1260,'BIG','Frankie and the Witch Fingers'],[1290,'LITTLE','Josh and the Dirty Rags'],[1320,'WOOD','American Sharks'],
[1380,'BIG','Shannon and the Clams'],[1410,'LITTLE','Bask'],[1440,'WOOD','Bosko Baker'],
[1500,'BIG','Deady']
]},
{ key:'SAT', label:'Saturday', tab:'SAT', date:'Sept 5', iso:'2026-09-05', color:'#E86A2E', sets:[
[540,'BIG','Yoga'],[600,'CAMP','Danza Azteca'],[540,'KICKIT','Rock N Roll Rock Painting with Crys'],[600,'LITTLE','Circus Flow Jam'],[660,'BIG','Barcode'],[660,'KICKIT','Guerrilla Gardening with Hilary and Friends'],[690,'LITTLE','Leo Crafft'],
[720,'WOOD','Burning Death'],[720,'KICKIT','Muddy Record Swap with Jon'],[720,'BIG','Craft Beer Tasting & Swap'],[780,'BIG','The Hotrails'],[810,'LITTLE','Maybels Fables'],[840,'WOOD','Buzzard Fight'],[840,'KICKIT','Kids Bandanna Decorating with Ersa'],
[900,'BIG','Meredith Moon'],[930,'LITTLE','Pollute'],[960,'WOOD','Zander Schloss'],
[1020,'BIG','Gumm'],[1050,'LITTLE','Psychic Death'],[1080,'WOOD',"Blossomin' Bone"],
[1140,'BIG',"Rickshaw Billie's Burger Patrol"],[1170,'LITTLE','Summer Newman'],[1200,'WOOD','Bloodshot Bill'],
[1260,'BIG','Municipal Waste'],[1290,'LITTLE','Sex Mex'],[1320,'WOOD',"Yes Ma'am"],
[1380,'BIG','Circle Jerks'],[1410,'LITTLE','Los Pistoleros'],[1440,'WOOD','Johanna Rose'],
[1500,'BIG','Mangy Bones']
]},
{ key:'SUN', label:'Sunday', tab:'SUN', date:'Sept 6', iso:'2026-09-06', color:'#DE2B1E', sets:[
[540,'BIG','Yoga'],[600,'LITTLE','Church'],[600,'KICKIT','Battle Jacket Design+ with Maxwell'],[630,'LITTLE','Gospel Hour'],[660,'BIG','Knifey'],[720,'KICKIT','Clothing Swap with Ersa'],
[690,'LITTLE','Runt'],[720,'WOOD','Rotten Luck'],[780,'BIG','Nightfreak'],[810,'LITTLE','Commander Keen'],
[840,'WOOD','A.P. Rodgers'],[900,'BIG','Filthy Still'],[930,'LITTLE','Jay Bird'],[960,'WOOD','James Hunnicutt'],
[1020,'BIG','The Tillers'],[1050,'LITTLE','Keddies Resort'],[1080,'WOOD','Bronco'],
[1140,'BIG','Son Rompe Pera'],[1170,'LITTLE','Hobo Gadget Junk Band'],[1200,'WOOD','Pat and the Pissers'],
[1260,'BIG','Mac Sabbath'],[1290,'LITTLE','Labretta Suede and The Motel 6'],[1320,'WOOD','The Builders and the Butchers'],
[1380,'BIG','Monolord'],[1410,'LITTLE','Black Tarpoon'],[1440,'WOOD','Wynton Existing']
]}
];
var ACTIVITIES = [
{ name: 'Waterfall', when: 'Friday-Sunday 10AM-6PM', where: '$6 round trip shuttle' },
{ name: 'Storytime with Rebekah', when: 'Friday 9AM', where: 'Kick It Tent' },
{ name: 'Yoga with Matt', when: 'Friday-Sunday 9AM', where: 'Big Tent', note: '1 hour class' },
{ name: 'Scrapbook Class with Maddie', when: 'Friday 10AM', where: 'Kick It Tent', note: '2 hour class' },
{ name: 'Friends of Bill W. with Luna', when: 'Friday-Sunday 11AM', where: '' },
{ name: 'Poetry Workshop with Emily', when: 'Friday 12PM', where: 'Kick It Tent' },
{ name: 'Tattoo Shop on Vendor Row', when: 'Friday-Sunday 12PM to close', where: 'behind Kick It Tent' },
{ name: 'Rock N Roll Rock Painting with Crys', when: 'Saturday 9AM', where: 'Kick It Tent', note: 'good for all ages' },
{ name: 'Circus Flow Jam with Windup', when: 'Saturday 10AM', where: 'Little Tent' },
{ name: 'Guerrilla Gardening with Hilary and Friends', when: 'Saturday 11AM', where: 'Kick It Tent', note: '1 hour class' },
{ name: 'Craft Beer Tasting & Swap', when: 'Saturday 12PM', where: 'back of Big Tent' },
{ name: 'Muddy Record Swap with Jon', when: 'Saturday 12PM', where: 'Kick It Tent' },
{ name: 'Kids Bandanna Decorating with Ersa', when: 'Saturday 2PM', where: 'Kick It Tent', note: 'we provide the bandannas' },
{ name: 'Church with Reverend Ben', when: 'Sunday 10AM', where: 'Little Tent' },
{ name: 'Battle Jacket Design+ with Maxwell', when: 'Sunday 10AM', where: 'Kick It Tent' },
{ name: 'Clothing Swap with Ersa', when: 'Sunday 12PM', where: 'Kick It Tent' },
{ name: 'Scavenger Hunt with Crys', when: 'Every day', where: 'clues posted by 9AM on Vendor Row', note: '7 winners each day' },
{ name: 'Camp Jams', when: 'All weekend', where: 'happening all over the festival grounds' }
];
var state = { query:'', day:'THU', stage:'ALL', starredOnly:false, favs:{}, now:Date.now() };
try {
var saved = localStorage.getItem('mr26-favs');
if (saved) state.favs = JSON.parse(saved) || {};
} catch(e){}
function fmt(min){
var m = ((min % 1440) + 1440) % 1440;
var h = Math.floor(m/60), mm = String(m%60);
if (mm.length < 2) mm = '0'+mm;
var h12 = ((h+11)%12)+1;
return h12 + ':' + mm + ' ' + (h < 12 ? 'AM' : 'PM');
}
var ROWS = [];
DAYS.forEach(function(day){
var dayStart = new Date(day.iso + 'T00:00:00-05:00').getTime(); /* set times are Central (Cookeville, CDT in September) */
day.sets.forEach(function(s){
var min = s[0], stage = s[1], band = s[2], flag = s[3] || null;
var st = STAGES[stage];
ROWS.push({
id: day.key + '-' + min + '-' + stage,
day: day, min: min, stage: stage, band: band,
flag: flag, tbd: flag === 'tbd',
stageName: st.name, stageColor: st.color,
start: dayStart + min*60000,
end: dayStart + (min + st.dur)*60000,
text: (day.label + ' ' + day.date + ' ' + (flag === 'tbd' ? 'tbd' : fmt(min)) + ' ' + st.name + ' ' + band + ' ' + band.split('.').join('') + (flag ? ' more info soon' : '')).toLowerCase()
});
});
});
ROWS.sort(function(a,b){ return a.start - b.start; });
function saveFavs(){
try { localStorage.setItem('mr26-favs', JSON.stringify(state.favs)); } catch(e){}
}
function esc(s){ return s.replace(/&/g,'&').replace(/</g,'<').replace(/>/g,'>').replace(/"/g,'"'); }
var elSearch = document.getElementById('search');
var elClear = document.getElementById('clearBtn');
var elTabs = document.getElementById('dayTabs');
var elChips = document.getElementById('chipRow');
var elList = document.getElementById('list');
var elNote = document.getElementById('searchNote');
var elEmpty = document.getElementById('emptyBox');
var elEmptyHint = document.getElementById('emptyHint');
var elHint = document.getElementById('saveHint');
function render(){
var q = state.query.trim().toLowerCase();
var tokens = q ? q.split(/\s+/) : [];
elClear.style.display = tokens.length ? 'block' : 'none';
/* day tabs */
var tabsHtml = '';
DAYS.forEach(function(d){
var active = !tokens.length && state.day === d.key;
var st = active
? 'background:'+d.color+';color:#0B0A08;border:1px solid '+d.color
: 'background:transparent;color:'+d.color+';border:1px solid '+d.color+'66';
tabsHtml += '<button class="daytab" style="'+st+'" data-day="'+d.key+'">'+
'<span class="lbl">'+d.tab+'</span><span class="dt">'+d.date+'</span></button>';
});
var actActive = !tokens.length && state.day === 'ACT';
var actSt = actActive
? 'background:#D7CEC1;color:#0B0A08;border:1px solid #D7CEC1'
: 'background:transparent;color:#D7CEC1;border:1px solid #D7CEC166';
tabsHtml += '<button class="daytab" style="'+actSt+'" data-day="ACT">'+
'<span class="lbl">EXTRAS</span><span class="dt">Activities</span></button>';
elTabs.innerHTML = tabsHtml;
/* stage chips + starred */
var chips = [{key:'ALL',label:'All Stages',color:'#fff'}];
['WOOD','LITTLE','BIG','KICKIT','CAMP'].forEach(function(k){ chips.push({key:k,label:STAGES[k].name,color:STAGES[k].color}); });
var chipsHtml = '';
chips.forEach(function(c){
var active = state.stage === c.key;
var st = active
? 'background:'+c.color+';color:#0B0A08;border:1px solid '+c.color
: 'background:transparent;color:'+(c.color==='#fff'?'rgba(255,255,255,.8)':c.color)+';border:1px solid rgba(255,255,255,.2)';
chipsHtml += '<button class="chip" style="'+st+'" data-stage="'+c.key+'">'+c.label+'</button>';
});
var favCount = Object.keys(state.favs).length;
var starSt = state.starredOnly
? 'background:#F5D34C;color:#0B0A08;border:1px solid #F5D34C'
: 'background:transparent;color:#F5D34C;border:1px solid rgba(245,211,76,.4)';
chipsHtml += '<div class="gap"></div><button class="chip" style="'+starSt+'" id="starFilter">★ My Schedule'+
(favCount ? '<span style="margin-left:6px;opacity:.8">('+favCount+')</span>' : '')+'</button>';
elChips.innerHTML = chipsHtml;
/* visible rows */
var visible = ROWS.filter(function(r){
if (state.stage !== 'ALL' && r.stage !== state.stage) return false;
if (state.starredOnly && !state.favs[r.id]) return false;
if (tokens.length){
return tokens.every(function(t){ return r.text.indexOf(t) !== -1; });
}
return r.day.key === state.day;
});
/* now / next per stage */
var now = state.now, nowIds = {}, nextIds = {};
['WOOD','LITTLE','BIG','KICKIT','CAMP'].forEach(function(key){
var stageRows = ROWS.filter(function(r){ return r.stage === key; });
stageRows.forEach(function(r){ if (!r.tbd && now >= r.start && now < r.end) nowIds[r.id] = true; });
for (var i=0;i<stageRows.length;i++){
if (!stageRows[i].tbd && stageRows[i].start > now && stageRows[i].start - now <= 3*3600000){ nextIds[stageRows[i].id] = true; break; }
}
});
elNote.style.display = tokens.length ? 'block' : 'none';
/* Activities tab: a directory instead of timed rows */
if (state.day === 'ACT' && !tokens.length){
elChips.style.display = 'none';
var ah = '<div style="padding-top:18px">';
ah += '<div class="dayhead" style="background:#D7CEC1"><span class="dl">Activities</span><span class="dd">All Weekend</span></div>';
ah += '<div style="display:flex;flex-direction:column">';
ACTIVITIES.forEach(function(a){
ah += '<div class="actrow"><div class="act-name">'+esc(a.name)+'</div>';
ah += '<div class="act-meta">'+esc(a.when)+(a.where ? ' · '+esc(a.where) : '')+(a.note ? ' · '+esc(a.note) : '')+'</div></div>';
});
ah += '</div></div>';
elList.innerHTML = ah;
elEmpty.style.display = 'none';
elHint.textContent = state.starredOnly
? 'Saves your starred sets as one image. Your own personal set list.'
: 'Saves the whole schedule as one image. No reception needed.';
document.getElementById('saveBtn').innerHTML = '⤓ ' + (state.starredOnly ? 'Save My Schedule' : 'Save to Phone');
return;
}
elChips.style.display = '';
/* groups */
var html = '';
var any = false;
DAYS.forEach(function(d){
var sets = visible.filter(function(r){ return r.day.key === d.key; });
if (!sets.length) return;
any = true;
html += '<div style="padding-top:18px">';
html += '<div class="dayhead" style="background:'+d.color+'"><span class="dl">'+d.label+'</span><span class="dd">'+d.date+' · 2026</span></div>';
html += '<div style="display:flex;flex-direction:column">';
sets.forEach(function(r){
html += '<div class="setrow">';
html += '<div class="time">'+(r.tbd ? 'TBD' : fmt(r.min))+'</div>';
html += '<div class="mid"><span class="band">'+esc(r.band)+'</span>';
if (r.flag) html += '<span class="tbdbadge">More Info Soon</span>';
if (nowIds[r.id]) html += '<span class="nowbadge">● Now</span>';
if (nextIds[r.id]) html += '<span class="nextbadge">Up Next</span>';
html += '</div>';
html += '<span class="stagechip" style="color:'+r.stageColor+';border-color:'+r.stageColor+'55">'+r.stageName+'</span>';
html += '<button class="starbtn" data-star="'+r.id+'" title="Add to my schedule" style="color:'+(state.favs[r.id]?'#F5D34C':'rgba(255,255,255,.35)')+'">'+(state.favs[r.id]?'★':'☆')+'</button>';
html += '</div>';
});
html += '</div></div>';
});
elList.innerHTML = html;
elEmpty.style.display = any ? 'none' : 'block';
if (!any){
elEmptyHint.textContent = (state.starredOnly && !favCount)
? 'Tap the star on any set to build your own schedule.'
: 'Try a different search. Band, stage, day, or time.';
}
elHint.textContent = state.starredOnly
? 'Saves your starred sets as one image. Your own personal set list.'
: 'Saves the whole schedule as one image. No reception needed.';
document.getElementById('saveBtn').innerHTML = '⤓ ' + (state.starredOnly ? 'Save My Schedule' : 'Save to Phone');
}
/* events (delegated) */
elTabs.addEventListener('click', function(e){
var b = e.target.closest('[data-day]');
if (!b) return;
state.day = b.getAttribute('data-day');
state.query = '';
elSearch.value = '';
render();
});
elChips.addEventListener('click', function(e){
var s = e.target.closest('[data-stage]');
if (s){ state.stage = s.getAttribute('data-stage'); render(); return; }
if (e.target.closest('#starFilter')){ state.starredOnly = !state.starredOnly; render(); }
});
elList.addEventListener('click', function(e){
var b = e.target.closest('[data-star]');
if (!b) return;
var id = b.getAttribute('data-star');
if (state.favs[id]) delete state.favs[id]; else state.favs[id] = true;
saveFavs();
render();
});
elSearch.addEventListener('input', function(){
state.query = elSearch.value;
render();
});
elClear.addEventListener('click', function(){
state.query = '';
elSearch.value = '';
render();
elSearch.focus();
});
setInterval(function(){ state.now = Date.now(); render(); }, 30000);
if (document.fonts && document.fonts.load){
document.fonts.load('60px Anton');
document.fonts.load('600 30px Oswald');
document.fonts.load('700 26px Oswald');
}
document.body.setAttribute('data-mr-sched', 'v8');
/* ---- Saving: every device gets a path that ends in the photo app ----
Desktop: normal file download.
Phones and tablets (iOS + Android): the native share sheet; "Save Image" puts it in Photos.
In-app browsers (Instagram, Facebook) and anything else: a press-and-hold panel. */
function isTouchDevice(){
return (window.matchMedia && matchMedia('(pointer: coarse)').matches) || 'ontouchstart' in window;
}
function showSaveModal(blobUrl, name){
var old = document.getElementById('saveModal');
if (old) old.parentNode.removeChild(old);
var m = document.createElement('div');
m.className = 'savemodal'; m.id = 'saveModal';
m.innerHTML =
'<div class="t">Your schedule is ready</div>' +
'<img src="' + blobUrl + '" alt="Muddy Roots 2026 schedule image">' +
'<div class="s">Press and hold the image, then tap Save Image (iPhone) or Download image (Android) to put it in your photos.</div>' +
'<a class="dl" href="' + blobUrl + '" download="' + name + '">Download PNG</a>' +
'<button class="close" type="button">Close</button>';
m.querySelector('.close').addEventListener('click', function(){
m.parentNode.removeChild(m);
});
document.body.appendChild(m);
}
function deliverBlob(blob, name, done){
var canFile = false;
var file = null;
try {
file = new File([blob], name, { type: 'image/png' });
canFile = !!(navigator.canShare && navigator.share && navigator.canShare({ files: [file] }));
} catch(e){ canFile = false; }
if (isTouchDevice() && canFile){
navigator.share({ files: [file], title: 'Muddy Roots 2026 Schedule' }).then(done, function(err){
if (!err || err.name !== 'AbortError') showSaveModal(URL.createObjectURL(blob), name);
done();
});
return;
}
if (!isTouchDevice()){
var url = URL.createObjectURL(blob);
var a = document.createElement('a');
a.href = url; a.download = name;
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
setTimeout(function(){ URL.revokeObjectURL(url); }, 60000);
done();
return;
}
showSaveModal(URL.createObjectURL(blob), name);
done();
}
var saving = false;
document.getElementById('saveBtn').addEventListener('click', function(){
if (saving) return;
var favsOnly = state.starredOnly;
var favs = state.favs;
var rows = ROWS.filter(function(r){ return !favsOnly || favs[r.id]; });
if (!rows.length){
elHint.textContent = 'No starred sets yet. Tap the star on any set first, then save.';
return;
}
var name = favsOnly ? 'muddy-roots-2026-my-schedule.png' : 'muddy-roots-2026-schedule.png';
saving = true;
var released = false;
var release = function(){ if (!released){ released = true; saving = false; } };
setTimeout(release, 12000);
var go = function(){
var W = 1080, rowH = 48, dayH = 108, topH = 200, footH = 138;
var byDay = DAYS.map(function(d){ return { d:d, sets: rows.filter(function(r){ return r.day.key === d.key; }) }; })
.filter(function(g){ return g.sets.length; });
var H = topH + byDay.reduce(function(a,g){ return a + dayH + g.sets.length*rowH + 26; }, 0) + footH;
var canvas = document.createElement('canvas');
canvas.width = W; canvas.height = H;
var ctx = canvas.getContext('2d');
ctx.fillStyle = '#0B0A08'; ctx.fillRect(0,0,W,H);
ctx.fillStyle = '#fff'; ctx.font = '58px Anton'; ctx.textBaseline = 'alphabetic';
ctx.fillText('MUDDY ROOTS MUSIC FESTIVAL', 48, 88);
ctx.fillStyle = ACCENT; ctx.font = '600 30px Oswald';
ctx.fillText((favsOnly ? 'MY SCHEDULE' : '2026 SCHEDULE') + ' \u00B7 SEPT 3-6 \u00B7 COOKEVILLE, TN', 48, 138);
ctx.strokeStyle = '#2c261f'; ctx.lineWidth = 2;
ctx.beginPath(); ctx.moveTo(48,168); ctx.lineTo(W-48,168); ctx.stroke();
var y = topH;
byDay.forEach(function(g){
ctx.fillStyle = g.d.color;
ctx.fillRect(48, y, W-96, 72);
ctx.fillStyle = '#0B0A08'; ctx.font = '40px Anton';
ctx.fillText(g.d.label.toUpperCase(), 72, y+50);
ctx.font = '700 26px Oswald'; ctx.textAlign = 'right';
ctx.fillText(g.d.date.toUpperCase(), W-72, y+48);
ctx.textAlign = 'left';
y += dayH;
g.sets.forEach(function(r){
ctx.fillStyle = 'rgba(255,255,255,.62)'; ctx.font = '600 27px Oswald';
ctx.textAlign = 'right'; ctx.fillText(r.tbd ? 'TBD' : fmt(r.min), 168, y);
ctx.textAlign = 'left';
ctx.fillStyle = r.stageColor;
ctx.beginPath(); ctx.arc(196, y-9, 7, 0, 7); ctx.fill();
ctx.fillStyle = '#fff'; ctx.font = '30px Anton';
ctx.fillText((favs[r.id] ? '\u2605 ' : '') + r.band.toUpperCase() + (r.flag ? ' (MORE INFO SOON)' : ''), 220, y+1);
ctx.fillStyle = r.stageColor; ctx.font = '600 24px Oswald'; ctx.textAlign = 'right';
ctx.fillText(r.stageName.toUpperCase(), W-52, y);
ctx.textAlign = 'left';
y += rowH;
});
y += 26;
});
ctx.fillStyle = 'rgba(255,255,255,.45)'; ctx.font = '600 22px Oswald';
ctx.fillText('FREE CAMPING \u00B7 FREE SHOWERS \u00B7 ALL TIMES CENTRAL \u00B7 SET TIMES SUBJECT TO CHANGE \u00B7 MUDDYROOTS.COM', 48, H-84);
ctx.fillStyle = ACCENT; ctx.font = '600 24px Oswald';
ctx.fillText('QUESTIONS? NEED ANYTHING? TEXT THE MUDDY HOTLINE: 615-437-6182', 48, H-40);
ctx.fillStyle = 'rgba(255,255,255,.35)'; ctx.font = '600 20px Oswald'; ctx.textAlign = 'right';
ctx.fillText('V8', W-52, H-40);
ctx.textAlign = 'left';
if (canvas.toBlob){
canvas.toBlob(function(blob){
if (blob) deliverBlob(blob, name, release);
else { showSaveModal(canvas.toDataURL('image/png'), name); release(); }
}, 'image/png');
} else {
showSaveModal(canvas.toDataURL('image/png'), name);
release();
}
};
if (document.fonts && document.fonts.load){
Promise.all([
document.fonts.load('60px Anton'),
document.fonts.load('600 30px Oswald'),
document.fonts.load('700 26px Oswald')
]).then(go, go);
} else { go(); }
});
render();
})();
</script>
```
## 5. Verify (walk every one of these)
- [ ] Page loads at `muddyroots.com/tennessee/schedule` with the dark schedule design, no Squarespace header or footer visible.
- [ ] Compare side by side with https://muddyrootsworldwide.com/tennessee/schedule/ at desktop and phone widths. Pixel for pixel.
- [ ] Four day tabs work: THURS, FRI, SAT, SUN. Saturday shows Circus Flow Jam at 10:00 AM on Little Tent.
- [ ] Stage chips filter: All Stages, Wood Stage, Little Tent, Big Tent, Kick It Tent, Not in Tent.
- [ ] Saturday shows Danza Azteca at 10:00 AM with a Not in Tent chip. Thursday's Campfire Jam shows Not in Tent with a More Info Soon badge.
- [ ] The Kick It Tent workshops appear: Storytime (Fri 9 AM), Scrapbook Class (Fri 10 AM), Poetry Workshop (Fri 12 PM), Rock Painting (Sat 9 AM), Guerrilla Gardening (Sat 11 AM), Record Swap (Sat 12 PM), Kids Bandanna Decorating (Sat 2 PM), Battle Jacket Design+ (Sun 10 AM), Clothing Swap (Sun 12 PM).
- [ ] The fifth tab, EXTRAS / Activities, lists 18 activities with times and places, and the stage chips hide while it is open.
- [ ] Search works across all days (try `municipal`, expect Municipal Waste on Saturday).
- [ ] Tapping the star on a set turns it yellow, survives a page reload, and My Schedule shows only starred sets with a count.
- [ ] Save behavior per device (test the PUBLISHED page, not the editor):
- Desktop: clicking `Save to Phone` downloads `muddy-roots-2026-schedule.png`.
- iPhone and Android (Safari or Chrome): tapping it opens the native share sheet; choosing `Save Image` puts the PNG in the photo app.
- Instagram or Facebook in-app browser: a dark panel appears with the image and press-and-hold instructions.
- [ ] Open the saved PNG: every day is listed, the line above last reads `ALL TIMES CENTRAL`, and the LAST line reads `QUESTIONS? NEED ANYTHING? TEXT THE MUDDY HOTLINE: 615-437-6182` in red.
- [ ] Star two sets, turn on `My Schedule`: the red button now reads `Save My Schedule` and saving produces `muddy-roots-2026-my-schedule.png` with only the starred sets.
- [ ] With `My Schedule` on and zero stars, tapping save shows the message `No starred sets yet. Tap the star on any set first, then save.`
- [ ] The page footer includes `All times Central` and the PNG footer line includes `ALL TIMES CENTRAL`.
- [ ] The footer link goes to `https://www.muddyroots.com/tennessee`.
- [ ] No em dashes anywhere on the page.