diff --git a/js/studio.js b/js/studio.js
index 87edd06..5976cdc 100644
--- a/js/studio.js
+++ b/js/studio.js
@@ -479,8 +479,8 @@ a{color:#e3e6eb}
curl -fsSL https://${esc(name)}/install.sh | sh
Configure
What to edit and where it lives. Say what the defaults are so most readers can stop here.
- Key Default What it does
- port 8080 Where it listens. data_dir ./data Where state is kept. log_level info How loud it is.
+ Key Default What it does
+ port 8080 Where it listens. data_dir ./data Where state is kept. log_level info How loud it is.
First run
The happy path, end to end, with the output the reader should actually see.
Note Anything that will bite a reader at 2am goes in a box like this one.
@@ -666,7 +666,7 @@ body{margin:0;background:#fdf6ec;color:#3a2a1c;font-family:Georgia,'Times New Ro
- Hold my seat
+ Hold my seat
This form needs somewhere to post to. Until you set one up, put an email address here instead.
@@ -709,7 +709,7 @@ body{margin:0;background:#fff9f2;color:#2f2418;font-family:system-ui,-apple-syst
Say what is in it and how often it lands. Then say what you will never do with the address — people read that line.
No tracking pixels. Unsubscribe from the bottom of any issue.
@@ -807,7 +807,7 @@ body{margin:0;background:#0a0c08;color:#eef3e4;font-family:system-ui,-apple-syst
Opening 14 November ${new Date().getFullYear()} — edit these numbers by hand, or drop in the Countdown widget from the Widgets panel to make them run.
or follow along: Nostr · Mastodon · Email
@@ -982,7 +982,7 @@ function setupEditing() {
}
// 4. Ready-made sections, Tilda style: drop, then edit text and images in place.
const bm = editor.BlockManager;
- const sec = (id, label, html, css) => bm.add(`sx-${id}`, { label, category: "Sections", media: SECTION_ICON, content: `${html}` });
+ const sec = (id, label, html, css, icon = SECTION_ICON) => bm.add(`sx-${id}`, { label, category: "Sections", media: icon, content: `${html}` });
sec("hero", "Hero", `NEW
A headline that earns the scroll One sentence on what this is and who it is for. Keep it honest and short.
Get started `,
`.sx-hero{padding:96px 24px;background:#0b0e14;color:#f1f4fa;text-align:center}.sx-wrap{max-width:820px;margin:0 auto}.sx-kicker{letter-spacing:.2em;font-size:12px;color:#d6ff3d;margin:0 0 12px}.sx-hero h1{font-size:44px;line-height:1.1;margin:0 0 16px}.sx-lead{font-size:18px;color:#b8c2d4;margin:0 0 28px}.sx-btn{display:inline-block;background:#d6ff3d;color:#0b0e14;padding:12px 22px;border-radius:10px;text-decoration:none;font-weight:600}`);
sec("features", "Three features", `Fast Say what it does in one line.
Simple Say why it is easy.
Yours Say what the visitor keeps.
`,
@@ -997,16 +997,44 @@ function setupEditing() {
`.sx-price{padding:64px 24px;background:#f6f7f9;color:#111}.sx-price .sx-grid3{max-width:1000px;margin:0 auto;display:grid;grid-template-columns:repeat(auto-fit,minmax(240px,1fr));gap:20px}.sx-plan{background:#fff;border:1px solid #e6e8ee;border-radius:16px;padding:28px 24px;text-align:center}.sx-hot{border-color:#111}.sx-amt{font-size:40px;font-weight:700;margin:8px 0 16px}.sx-plan ul{list-style:none;padding:0;margin:0 0 20px;color:#555;line-height:1.9}.sx-price .sx-btn{display:inline-block;background:#111;color:#fff;padding:10px 20px;border-radius:10px;text-decoration:none;font-weight:600}`);
sec("cta", "Call to action", ``,
`.sx-cta{padding:72px 24px;text-align:center;background:#d6ff3d;color:#0b0e14}.sx-cta h2{font-size:34px;margin:0 0 8px}.sx-cta p{margin:0 0 24px;font-size:17px}.sx-cta .sx-btn{display:inline-block;background:#0b0e14;color:#d6ff3d;padding:12px 22px;border-radius:10px;text-decoration:none;font-weight:600}`);
- sec("contact", "Contact form", ``,
+ sec("contact", "Contact form", ``,
`.sx-contact{padding:64px 24px;background:#fff;color:#111}.sx-contact .sx-wrap{max-width:560px;margin:0 auto}.sx-contact h2{margin:0 0 16px}.sx-form{display:grid;gap:10px}.sx-form input,.sx-form textarea{width:100%;padding:12px;border:1px solid #d9dce3;border-radius:10px;font:inherit}.sx-contact .sx-btn{background:#111;color:#fff;border:0;padding:12px 20px;border-radius:10px;font-weight:600;cursor:pointer}`);
sec("footer", "Footer", ``,
`.sx-footer{padding:28px 24px;background:#0b0e14;color:#b8c2d4;font-size:14px}.sx-foot-in{max-width:1000px;margin:0 auto;display:flex;justify-content:space-between;gap:14px;flex-wrap:wrap}.sx-footer a{color:#b8c2d4;text-decoration:none;margin-left:16px}.sx-footer b{color:#f1f4fa}`);
+ // Ten more, added 2026-09: navigation, social proof and the small print
+ // that every real page ends up needing. Each block owns its own class
+ // namespace (.sx-nav1, .sx-faq, …) and never reuses a selector another
+ // block defines, so dropping two of them on one page cannot make the
+ // first one change shape. `data-gjs-type="text"` marks the elements the
+ // parser would otherwise treat as opaque — the editor eats the attribute,
+ // it never reaches the exported page.
+ sec("nav-simple", "Nav — simple", ``,
+ `.sx-nav1{background:#fff;border-bottom:1px solid #e8eaee}.sx-nav1-in{max-width:1040px;margin:0 auto;padding:16px 24px;display:flex;align-items:center;justify-content:space-between;gap:16px;flex-wrap:wrap}.sx-nav1-logo{color:#111;font-weight:700;font-size:16px;text-decoration:none}.sx-nav1-links a{color:#5a6069;text-decoration:none;font-size:14.5px;margin-left:22px}.sx-nav1-links a:hover{color:#111}@media(max-width:480px){.sx-nav1-links a{margin:0 16px 0 0}}`, NAV_ICON);
+ sec("nav-cta", "Nav — with button", ``,
+ `.sx-nav2{background:#0b0e14;color:#f1f4fa}.sx-nav2-in{max-width:1100px;margin:0 auto;padding:14px 24px;display:flex;align-items:center;gap:18px;flex-wrap:wrap}.sx-nav2-logo{color:#f1f4fa;font-weight:700;font-size:16px;text-decoration:none;margin-right:10px}.sx-nav2-links{flex:1;display:flex;gap:22px;flex-wrap:wrap}.sx-nav2-links a{color:#9aa4b5;text-decoration:none;font-size:14.5px}.sx-nav2-links a:hover{color:#fff}.sx-nav2-btn{background:#d6ff3d;color:#0b0e14;font-weight:700;font-size:14px;padding:9px 18px;border-radius:9px;text-decoration:none;white-space:nowrap}`, NAV_ICON);
+ sec("video-hero", "Video hero", `Say it over moving pictures Click the video and set its source in the panel on the right — an MP4 you uploaded works, and so does any public URL. Until then the gradient stands in.
Watch the film `,
+ `.sx-vhero{position:relative;min-height:70vh;display:flex;align-items:center;justify-content:center;text-align:center;padding:80px 24px;overflow:hidden;background:linear-gradient(140deg,#131a2b,#2c1a3a 55%,#0b0e14)}.sx-vhero-bg{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;border:0}.sx-vhero-in{position:relative;max-width:720px;color:#fff;text-shadow:0 2px 24px rgba(0,0,0,.55)}.sx-vhero h1{font-size:46px;line-height:1.1;margin:0 0 14px;letter-spacing:-.02em}.sx-vhero p{font-size:17px;color:rgba(255,255,255,.82);margin:0 0 26px}.sx-vhero-btn{display:inline-block;background:#fff;color:#111;font-weight:700;padding:13px 26px;border-radius:999px;text-decoration:none}@media(max-width:600px){.sx-vhero h1{font-size:30px}}`);
+ sec("stats", "Big numbers", `12k names registered
99.9% gateway uptime
4 chains supported
$0 renewal fees, ever
`,
+ `.sx-stat{padding:56px 24px;background:#f6f7f9;color:#111}.sx-stat-in{max-width:1000px;margin:0 auto;display:grid;grid-template-columns:repeat(auto-fit,minmax(150px,1fr));gap:32px;text-align:center}.sx-stat b{display:block;font-size:44px;font-weight:700;letter-spacing:-.03em;line-height:1.05;font-variant-numeric:tabular-nums}.sx-stat span{display:block;margin-top:6px;color:#6b727c;font-size:14px}`);
+ sec("steps", "Numbered steps", `How it works 1 Pick a name Search, check it is free, pay once.
2 Build the page Drag sections in, rewrite the words.
3 Publish One click puts it on Sia, signed by you.
`,
+ `.sx-steps{padding:64px 24px;background:#fff;color:#111}.sx-steps>h2{max-width:1000px;margin:0 auto 32px;font-size:28px;letter-spacing:-.015em}.sx-steps-in{max-width:1000px;margin:0 auto;display:grid;grid-template-columns:repeat(auto-fit,minmax(210px,1fr));gap:28px}.sx-step-n{display:inline-flex;align-items:center;justify-content:center;width:36px;height:36px;border-radius:50%;background:#111;color:#fff;font-weight:700;font-size:16px;margin-bottom:12px}.sx-step h3{margin:0 0 6px;font-size:18px}.sx-step p{margin:0;color:#5a6069;line-height:1.6}`);
+ sec("team", "Team", `Who you would be working with A. Person Founder One line on what they do and what they did before.
B. Person Design One line on what they do and what they did before.
C. Person Engineering One line on what they do and what they did before.
`,
+ `.sx-team{padding:64px 24px;background:#fff;color:#111}.sx-team>h2{max-width:980px;margin:0 auto 34px;font-size:28px;letter-spacing:-.015em}.sx-team-in{max-width:980px;margin:0 auto;display:grid;grid-template-columns:repeat(auto-fit,minmax(200px,1fr));gap:34px}.sx-member img{width:96px;height:96px;border-radius:50%;object-fit:cover;background:#eceef1;display:block;margin-bottom:14px}.sx-member b{display:block;font-size:16px}.sx-member i{display:block;font-style:normal;color:#8b9099;font-size:13.5px;margin-bottom:8px}.sx-member p{margin:0;color:#5a6069;font-size:15px;line-height:1.6}`);
+ sec("logos", "Logo cloud", `Trusted by people who read the source
${Array.from({ length: 6 }, () => `
`).join("")}
`,
+ `.sx-logos{padding:48px 24px;background:#fafbfc;border-top:1px solid #eceef1;border-bottom:1px solid #eceef1}.sx-logos-lab{max-width:1000px;margin:0 auto 26px;text-align:center;font-size:12px;letter-spacing:.14em;text-transform:uppercase;color:#98a0ab}.sx-logos-in{max-width:1000px;margin:0 auto;display:flex;flex-wrap:wrap;align-items:center;justify-content:center;gap:24px 48px}.sx-logos img{height:34px;width:auto;filter:grayscale(1);opacity:.6;transition:filter .18s,opacity .18s}.sx-logos img:hover{filter:none;opacity:1}`);
+ sec("timeline", "Timeline", `How we got here 2021 It started as a weekend thing What happened, in one or two sentences.
2023 The first real users What happened, in one or two sentences.
2024 It paid for itself What happened, in one or two sentences.
Today Where it is now What happened, in one or two sentences.
`,
+ `.sx-tl{padding:64px 24px;background:#0b0e14;color:#e8ecf2}.sx-tl>h2{max-width:720px;margin:0 auto 34px;font-size:28px;letter-spacing:-.015em}.sx-tl-in{max-width:720px;margin:0 auto;border-left:2px solid #232a36;padding-left:26px}.sx-tl-row{position:relative;padding-bottom:28px}.sx-tl-row:last-child{padding-bottom:0}.sx-tl-row::before{content:"";position:absolute;left:-33px;top:6px;width:12px;height:12px;border-radius:50%;background:#d6ff3d}.sx-tl-row time{display:block;font-size:13px;letter-spacing:.06em;color:#d6ff3d;margin-bottom:4px}.sx-tl-row b{display:block;font-size:17px;margin-bottom:4px}.sx-tl-row p{margin:0;color:#98a3b4;line-height:1.6}`);
+ sec("faq", "FAQ", `Questions people actually ask What happens if this site goes away? Answer it straight. The shortest true answer builds more trust than the longest reassuring one.
Do I need a wallet? Answer it straight.
What does it cost, in total? Answer it straight.
Can I move it somewhere else later? Answer it straight.
Who can see what I publish? Answer it straight.
How do I get help? Answer it straight.
`,
+ `.sx-faq{padding:64px 24px;background:#fff;color:#111}.sx-faq>h2{max-width:720px;margin:0 auto 26px;font-size:28px;letter-spacing:-.015em}.sx-faq-in{max-width:720px;margin:0 auto}.sx-faq-i{border-bottom:1px solid #e8eaee}.sx-faq-i summary{cursor:pointer;padding:16px 28px 16px 0;font-size:17px;font-weight:600;position:relative;list-style:none}.sx-faq-i summary::-webkit-details-marker{display:none}.sx-faq-i summary::after{content:"+";position:absolute;right:4px;top:14px;font-size:20px;font-weight:400;color:#98a0ab}.sx-faq-i[open] summary::after{content:"–"}.sx-faq-i p{margin:0 0 18px;color:#5a6069;line-height:1.65;max-width:62ch}`);
+ sec("newsletter", "Signup band", ``,
+ `.sx-news{padding:52px 24px;background:#d6ff3d;color:#0b0e14}.sx-news-in{max-width:1000px;margin:0 auto;display:flex;align-items:center;justify-content:space-between;gap:32px;flex-wrap:wrap}.sx-news h2{margin:0 0 6px;font-size:26px;letter-spacing:-.015em}.sx-news p{margin:0;font-size:15.5px;opacity:.75;max-width:46ch}.sx-news-form{display:flex;gap:8px;flex-wrap:wrap;flex:1;min-width:280px;max-width:440px}.sx-news-form input{flex:1;min-width:180px;padding:13px 15px;border:1px solid rgba(11,14,20,.22);border-radius:10px;font:inherit;background:#fff}.sx-news-form button{padding:13px 22px;border:0;border-radius:10px;background:#0b0e14;color:#d6ff3d;font:inherit;font-weight:700;cursor:pointer}`);
// Group the plugin blocks under readable categories.
const cat = { navbar: "Sections", tabs: "Widgets", tooltip: "Widgets", "custom-code": "Widgets", countdown: "Widgets" };
bm.getAll().forEach((b) => { const c = cat[b.getId()]; if (c) b.set("category", c); });
// 5. Selecting anything opens the style panel; the layer tree is one click away.
editor.on("component:selected", () => { const btn = editor.Panels.getButton("views", "open-sm"); if (btn && !btn.get("active")) btn.set("active", true); });
}
+const NAV_ICON = ` `;
const SECTION_ICON = ` `;
function loadTemplate(key) {