Changelog — Site Builder
All notable changes to this app are recorded here. Newest entries on top.
[2026-05-26]
- Fixed the admin "Impersonating …" chip leaking onto published sites and breaking saves on custom domains. While impersonating a user, the chip was being injected into that user's live custom-domain site (and the editor canvas). On a custom domain its "Stop" button led to a 404, and because the injected markup made the page longer than its declared size, the browser truncated the response — so a freshly published edit would flash on screen and then vanish on refresh. Worse, when the chip landed inside the editor canvas it could get serialized into the saved page, baking itself permanently into the published HTML (which then showed to every visitor, on every browser). Fixes: the chip is now shown only on the platform's own pages (never on custom-domain sites or inside the editor canvas), "Stop" works reliably, and a server-side scrubber strips any chip that was already baked into a saved/published page when it's served — so the live site is cleaned immediately, no re-publish required. The editor also strips it on the next save.
[2026-05-25]
- Fixed missing icons and embeds on published sites served from a custom domain. Templates that pull Font Awesome icons, social logos, web fonts, or map/video embeds from third-party CDNs (Font Awesome via cdnjs, Google Fonts, Google Maps, etc.) rendered correctly in the editor and preview but lost those assets once published to a connected custom domain. The platform's strict security policy was being applied to the published page and silently blocking those external resources. Published custom-domain pages now load the same assets as the editor preview, so icons and embeds show up after publishing.
- Fixed a "Cannot read properties of undefined (reading 'doctype')" error and stuck "Saving …" spinner during editor load. If a save fired before the canvas had finished loading, the editor threw an error and the save indicator could hang. The editor now waits for the canvas to be ready and skips that early save instead of erroring — and never saves blank content, so a not-yet-loaded page can't overwrite your draft.
[2026-05-22]
- New template: Evermore — romantic wedding-invitation and save-the-date site for couples and wedding planners. Cream and white with a pink accent and an orange pop; condensed Bebas Neue display over Sen. The hero stacks the couple's names around a pink ampersand with the date, venue, a four-tile countdown, and an RSVP button beside an arched couple photo. Sections: a bride-and-groom couple block with circular portraits, a centered love-story timeline (met, first date, proposal, engagement) with alternating cards, a mixed-size "captured moments" gallery, two event-detail cards (ceremony & reception), and a full-pink RSVP form. Six photos + Bebas Neue/Sen (4 woff2) bundled locally. Pink-and-cream wedding — a brand-new genre in the gallery. This completes the Crafto modernization: all 55 demos rebuilt.
- New template: Kinetic — bold, dark site for web-design studios and digital agencies. Near-black with a single electric-lime accent; heavy Inter throughout. A giant-type hero ("We create unique digital experiences.") sits above a meta row (full-service · London · award-winning) and dual CTAs, followed by a lime scrolling discipline marquee. Sections: a numbered services list that insets on hover (web design, development, eCommerce, branding), a two-up work grid with lime category labels, an awards/recognition list, a full electric-lime four-stat band, and a glowing giant-type contact block. Four work photos + Inter (7 woff2) bundled locally. Neon-lime-on-dark agency, distinct from the yellow digital-agency neighbour via lime, Inter, and a services/awards layout.
- New template: Vert — calm, dark portfolio for designers, studios, and art directors. Deep forest-green with sage accents and soft sage glows; condensed Bebas Neue display over Albert Sans. A giant-type hero ("Design that grows on you.") leads into the signature — a vertically stacked set of full-width project panels that alternate image and text side (numbered, with category and a case-study link), collapsing to a clean stack on mobile. Sections also include a panelled studio about split with a sage-bordered portrait and a three-stat row, a numbered capabilities list, and a glowing giant-type contact block. Five photos + Bebas Neue/Albert Sans (4 woff2) bundled locally. Forest-green vertical-panel portfolio, distinct from the gold horizontal-index portfolio neighbour.
- New template: Voyage — wanderlust site for travel agencies, tour operators, and booking platforms. Cream and white with a tan-camel accent and a red price pop; Barlow Semi Condensed display over Schibsted Grotesk. A full-bleed beach hero carries a "Discover the world" headline and a trip-search bar (destination, dates, travellers). Sections: a four-tile prime-destinations grid, a three-card popular-packages grid with day badges, star ratings, and "Just $X" pricing, a dark four-stat band, a large traveller testimonial, and a full-bleed "get ready to explore" CTA. Eight travel photos + Barlow Semi Condensed/Schibsted Grotesk (11 woff2) bundled locally. Tan-and-cream travel with a trip-search and packages, distinct from the Rufina-serif resort neighbour.
- New template: Glide — modern site for startups, SaaS products, and business platforms. White with a teal-to-sky-blue gradient accent and a dark band; Manrope display over Rubik. The hero pairs a gradient "Run your business on autopilot" headline with a pure-CSS revenue-dashboard mockup — KPI tiles and a rising gradient bar chart in a browser frame. Sections: a client logo strip, a six-card feature grid with teal/blue icons, a three-step process, a dark four-stat band with gradient numerals, three pricing tiers with a dark featured plan, and a full-gradient "ready to glide?" CTA. No photos — all pure CSS. Manrope/Rubik (12 woff2) bundled locally. Teal-and-blue SaaS, distinct from the cooler-blue and emerald neighbours.
- New template: Lumea — serene site for spas, massage studios, and wellness clinics. Warm beige and white with a coral accent and dark-brown ink; Rufina serif (italic emphasis) over Jost. The hero pairs a "relax, restore, and renew" headline with an arched spa photograph and a coral circle accent. Sections: a six-card treatment menu with prices and durations (massage, aromatherapy, facial, body, scalp, sauna), a beige "100% natural & organic" about split with a coral year medallion and a checklist, three therapist cards, three therapy packages with a dark featured tier, and a full-bleed booking CTA. Five photos + Rufina/Jost (7 woff2) bundled locally. Coral-and-beige wellness, distinct from the yoga and beauty-salon neighbours via Rufina serif and a treatment-menu layout.
- New template: Uprise — energetic site for SEO, digital-marketing, and growth agencies. White with an indigo accent, a coral co-accent, and lavender/peach tints; Urbanist display over Atkinson Hyperlegible. The hero pairs a "power your online visibility" headline and a free-SEO-analysis bar ("enter your URL" + analyze) with a pure-CSS organic-traffic card — a rising bar chart (coral peak) over a live keyword-ranking list. Sections: a six-card service grid with alternating indigo/coral icons, a four-step lavender process, an indigo four-stat band, three pricing packages with a coral "popular" flag, and a full-coral "free SEO analysis" CTA. No photos — all pure CSS. Urbanist/Atkinson Hyperlegible (6 woff2) bundled locally. Indigo-and-coral marketing, distinct from the indigo-and-pastel recruitment neighbour.
- New template: Tilt — editorial, off-grid portfolio for creative directors, designers, and studios. Warm off-white and black with a bright-yellow highlight; Playfair Display serif (italic accents) over Manrope. The hero reads "Ideas worth tilting your head for." with a yellow swipe under the italic word. The signature is a deliberately scattered work section — five project tiles at varied sizes and staggered vertical offsets rather than a tidy grid (collapsing to a clean stack on mobile). Sections also include an about split with a yellow-square portrait, a numbered services list that insets on hover, and a big serif "let's work together" contact line. Six photos + Playfair Display/Manrope (14 woff2) bundled locally. Serif-and-yellow asymmetric portfolio, distinct from the sans minimal-portfolio neighbour.
- New template: Ember — moody site for grills, steakhouses, and upscale-casual restaurants. Dark charcoal with a warm gold accent, cream bands, and a red price pop; condensed Bebas Neue display over Schibsted Grotesk. A full-bleed grilled-food hero carries a "savor the finest flavors in town" headline and dual CTAs over a dark gradient. Sections: a gold three-feature strip (seasonal, open late, wood-fired), a cream popular-dishes grid with ratings and prices, a dark two-column dotted-leader menu (grill, starters), an our-story split with a gold "15 years" medallion and stats, and a full-bleed reservation CTA. Five food photos + Bebas Neue/Schibsted Grotesk (4 woff2) bundled locally. Dark-and-gold fine dining — deliberately moodier than the bright cream pizza neighbour.
- New template: Roster — clean recruitment and applicant-tracking SaaS site for hiring platforms, job boards, and HR tools. White with an indigo accent and soft lavender/mint/peach pastel tints; Inter Tight throughout. The hero pairs a "Hire better, faster." headline and a trust row with a pure-CSS "new applicants" job-board mockup — company-avatar rows with full-time/remote tags. Sections: a six-card feature grid where each card is a different pastel, a lavender three-step process, a four-card featured-jobs grid, and an indigo four-stat band, ending in a lavender "post your first job free" CTA. No photos — all pure CSS, so it stays fast and unmistakably a software product. Inter Tight (7 woff2) bundled locally. Indigo-and-pastel hiring tool, softer than the corporate-blue neighbours.
- New template: Abode — friendly site for real-estate agencies, property portals, and letting agents. White with a green accent, an amber pop, and pale-green bands; Urbanist display over the highly readable Atkinson Hyperlegible. A centered hero pairs a "find a place you'll love to call home" headline with a Buy/Rent/Sell search bar (location, type, price) above a wide home photo. Sections: a five-tile property-type grid with listing counts, a three-card featured-listings grid with for-sale/for-rent tags, prices, and beds/baths/sqft specs, a three-step how-it-works, a green four-stat band, and a pale-green "thinking of selling?" CTA. Four property photos + Urbanist/Atkinson Hyperlegible (6 woff2) bundled locally. Green-and-amber property layout, distinct from the eco-green and charity neighbours.
- New template: Flux — vivid product-showcase site for consumer electronics, gadgets, and hardware brands. White with a hot-pink-to-purple gradient accent and a dark spec band; bold Manrope type. The hero pairs a gradient "Sound, reimagined." headline with a product photo (soft gradient glow behind), a buy button, save badge, and colour swatches. Sections: a six-card exclusive-features grid, a dark "design" showcase band with a four-figure spec block and a gradient glow, three product tiers (Air / Pro 2 / Studio) with a gradient featured plan, three verified reviews, and a full-gradient "hear the difference" CTA. Two product photos + Manrope (6 woff2) bundled locally. Pink-to-purple gradient product page, distinct from the flat-pink music neighbour.
- New template: Forno — appetising site for pizzerias, trattorias, and Italian restaurants. Warm cream and white with a deep-red accent and a golden-yellow pop; condensed Antonio display over Schibsted Grotesk. The hero pairs a "the true taste of Italy" headline with a circular pizza photo ringed in dashed yellow and a rotated "30m delivery" badge. Sections: a red three-feature strip (special, fast delivery, food lovers), a four-card popular-pizza grid with hot/new badges, ratings, and prices, a two-column dotted-leader menu (pizza, pasta, dolci), an our-story split with a yellow "35 years" medallion and stats, three customer testimonials, and a red order CTA. Six food photos + Antonio/Schibsted Grotesk (4 woff2) bundled locally. Red-and-cream Italian warmth, unlike any neighbour.
- New template: Aperture — refined portfolio for photographers and studios. Off-white and near-black with a soft pale-mint accent; Schibsted Grotesk display over Poppins. The hero pairs a "Moments, made to last." headline with an arched hero photograph behind a mint circle. Sections: a four-stat strip, a mixed-size gallery with category filter pills and hover captions, an about split with a mint-circle portrait and a signature, three session packages with pricing, a large client quote, and a dark "let's make something beautiful" CTA. Eight photos + Schibsted Grotesk/Poppins (11 woff2) bundled locally. Mint-and-light gallery portfolio, distinct from the yellow minimal design-portfolio neighbour.
- New template: Resonance — bold one-page site for bands, solo artists, and DJs. Near-black with a hot-pink accent and a yellow pop; heavy condensed Anton display over Manrope, with neon-pink glows. A glowing giant-type hero ("Midnight Vibration") sits beside a live concert photo with dual CTAs. Sections: a four-up album grid with hover play buttons, a popular-tracklist with track numbers and play controls, a tour-dates list with venues and sold-out badges, a four-item achievements/awards row, and a neon "don't miss the noise" CTA. Five photos + Anton/Manrope (9 woff2) bundled locally. Dark neon-pink music energy, unlike any neighbour.
- New template: Vertex — modern site for growth agencies, consultancies, and B2B teams. White with lavender section tints and a vivid violet accent; DM Sans display over Inter. A soft lavender-gradient hero pairs a "business growth, to the next level" headline and a trust row with a team photo carrying a violet "+212% agency growth" card. Sections: a client logo strip, a six-service grid, a full violet stats band, a lavender why-us split with a checklist, a three-step framework, an FAQ accordion, and a dark violet-glow CTA. Two photos + DM Sans/Inter (9 woff2) bundled locally. Violet-and-lavender modern agency, distinct from the solid-indigo corporate neighbour.
- New template: Index — minimal portfolio for designers, art directors, and studios who value restraint. White and light-gray with a single bright-yellow highlight; Inter with generous whitespace. A big typographic hero ("Design with less, but better." — yellow highlight) and an "available for work" status dot lead into a clean two-up work grid with hover highlight, an about split, a numbered capabilities list that insets on hover, a selected-clients row, and an oversized email contact. Five photos + Inter (7 woff2) bundled locally. Light, airy, and minimal — the deliberate opposite of the dark giant-type portfolio neighbours.
- New template: Medora — calm, trustworthy site for hospitals, clinics, and medical centres. White with pale-cyan section bands, a teal accent, and a red emergency pop; bold Manrope type. The hero pairs a "your most trusted health partner" headline with an appointment widget (department + date + find-a-doctor) and a patient photo carrying a rating card. Sections: four overlapping quick-info cards (verified doctors, online booking, health records, a red 24/7 emergency), a six-card clinical-departments grid, a pale-cyan about split with a teal "25 years" badge and a checklist, a three-step booking flow, three doctor profile cards with ratings, and a teal appointment CTA with an emergency line. Five photos + Manrope (6 woff2) bundled locally. Teal-and-cyan hospital look, distinct from the navy-and-rose senior-care neighbour.
- New template: Amplify — results-driven site for marketing agencies, growth teams, and performance shops. White with an orange-coral primary, jungle-green and yellow pops, and dark-slate sections; bold Inter type. The hero pairs a "marketing that moves the numbers" headline (orange + yellow highlight) with a pure-CSS campaign-performance card — ROAS and lead KPIs plus an orange-to-green revenue bar chart. Sections: a client logo strip, a two-up services grid with multi-colour icons, a full jungle-green results band (revenue, ROAS, brands, retention), a three-step strategy process, three monthly pricing tiers with a featured dark plan, three testimonials, and a dark CTA with orange/green glows. Photo-light (pure-CSS hero) + Inter (7 woff2) bundled locally. Orange-green-yellow agency look, distinct from the coral magazine neighbour.
- New template: Dispatch — modern site for online magazines, editorial blogs, and digital publications. Warm white and near-black with a coral accent; bold Plus Jakarta Sans. A dated masthead bar and centered wordmark sit above a featured-story hero — a large gradient-overlaid lead article beside three stacked side stories with bylines. Sections: a "trending" category pill bar, a three-column latest-stories grid with coral category tags and hover, a dark editor's-pick band with a long-read feature, and a full-coral weekly-newsletter signup. Eleven editorial photos + Plus Jakarta Sans (4 woff2) bundled locally. Coral magazine grid, distinct from the warm-paper serif blogger neighbour.
- New template: Freightline — bold site for logistics companies, freight forwarders, and couriers. Black and white with an amber-yellow accent and a green status pop; heavy Urbanist type. A dark hero pairs a "delivered on time" headline with a shipment-tracking bar (tracking-number input + track button) and a freight photo carrying a yellow "99.6% on-time" card. Sections: a four-service grid (air, sea, road, warehousing), a why-us split with a yellow "25+ years" badge and a numbered list, a dark four-stat band (parcels, countries, fleet, reviews), a four-step how-it-works with ghost numerals, and a full-yellow quote CTA. Two photos + Urbanist (2 woff2) bundled locally. Amber-on-black logistics with a tracking motif, distinct from the run's other yellows.
- New template: Ashcroft & Vance — prestige site for law firms, attorneys, and legal practices. Deep slate-navy with a brass-gold accent and warm-cream section bands; Playfair Display serif (italic emphasis) over DM Sans. A dark slate hero pairs a "justice, pursued relentlessly" headline with a brass-framed photo, sitting above a dark result-stats bar (cases solved, clients, awards, success rate). Sections: a six-cell bordered practice-areas grid (corporate, real estate, family, criminal, injury, estate), a cream about split with a brass "30 years" badge and a checklist, three attorney profile cards with grayscale-to-colour hover, a dark italic client testimonial, and a full-brass consultation CTA. Five photos + Playfair Display/DM Sans (6 woff2) bundled locally. The dark slate hero keeps it firmly clear of the cream-serif look.
- New template: Lustre — elegant e-commerce for fine-jewellery brands, boutiques, and accessory labels. Warm white and blush with a rose-gold accent and espresso ink; light-weight Jost with italic accents and a centered wordmark nav over a dark promo bar. A blush split hero pairs a "jewellery for life's quiet moments" headline with a model photo. Sections: a three-tile shop-by-category grid (rings, earrings, necklaces) with gradient labels, a four-up bestsellers product grid with hover add-to-bag, material lines, and prices, an our-story split with a rose-bordered craft photo, a four-icon benefits row (shipping, support, returns, secure pay), a blush newsletter, and a four-column dark footer. Nine jewellery photos + Jost (3 woff2) bundled locally. Soft blush-and-rose-gold luxe, distinct from the bolder commerce neighbours.
- New template: Umbra — dark, bold portfolio for design studios, art directors, and creative agencies. Near-black with an antique-gold accent and soft gold glows; condensed Bebas Neue display over Inter. A giant-type hero ("We build brands that own the dark.") leads into the centerpiece — an interactive project index where each row is an oversized project name that insets and turns gold on hover, revealing a peek thumbnail beside it (category + year alongside). Sections: a panelled studio about split with a gold-bordered portrait and a three-stat row, a six-cell capabilities grid, a gold scrolling discipline marquee, and a glowing giant-type contact block. Six photos + Bebas Neue/Inter (9 woff2) bundled locally. Dark-and-antique-gold condensed portfolio with an interactive index — distinct from the magenta-serif and red giant-type portfolio neighbours.
- New template: Aurelia — elegant site for luxury hotels, resorts, and private retreats. Cream and near-black with a warm tan-gold accent; Rufina serif headlines over Urbanist. A full-bleed resort photo hero carries an overlay headline and a five-field booking widget (check-in, check-out, guests, room, check availability). Sections: a six-cell bordered facilities grid (pool, spa, dining, beach, concierge, gym), three suite cards with photo, "get X% off" offer badges and "starting from" pricing, a cream about split with a gold "Established 1998" badge, a mixed-size photo gallery, and a full-bleed dusk CTA. Ten resort photos + Rufina/Urbanist (6 woff2) bundled locally. Photo-rich tan-gold hospitality, distinct from the other gold-accented neighbours.
- New template: Catalyst — energetic site for IT-services firms, technology consultancies, and business-solution providers. White with a deep-blue primary and a lively coral secondary (plus a green accent), over a midnight industries band; bold Plus Jakarta Sans. The hero pairs a "we craft solutions that grow your business" headline (blue + coral highlights) and a trust row with a team photo carrying a coral "+38% growth" float card. Sections: three overlapping multi-colour feature cards (grow / cost-saving / performance), a six-service grid with alternating blue/coral icons, a midnight "industries we serve" band with a chip cloud and a four-stat strip, two client testimonials, and a blue CTA with a coral glow. One photo + Plus Jakarta Sans (4 woff2) bundled locally. Blue-and-coral, deliberately warmer than the cool blue hosting neighbour.
- New template: Nimbus — clean web-hosting and cloud product site for hosts, domain registrars, and SaaS infrastructure. White with an electric royal-blue accent and an emerald uptime-green, plus dark-navy panels; bold Inter type. The hero pairs a "hosting that just works" headline and a domain-search bar (input + .com + search) with a pure-CSS dark "server status" panel — uptime/response metrics and a live list of online sites with green dots. Sections: a four-card products grid (web hosting, online store, business email, cloud storage), three pricing tiers with a highlighted "most popular" plan, a three-step "live in three steps" how-it-works, a dark uptime stats band, an FAQ accordion, and a blue rounded CTA. No photos — all pure CSS, so it's fast and unmistakably a tech product. Inter (7 woff2) bundled locally.
- New template: Iris — dark, elegant portfolio for creative studios, designers, and art directors. Near-black canvas with a single hot-magenta accent and soft radial magenta glows; Prata Didone serif (with italic emphasis) over Inter. The hero is a large serif statement ("Design that turns heads…") with a magenta-underlined eyebrow and dual CTAs, followed by a horizontal scroll-snap work strip of project cards (category, title, year). Sections: a panelled studio about split with a magenta-bordered portrait and a three-stat row, a numbered capabilities list that insets on hover, a two-up featured-projects grid with gradient overlays, a centered client wordmark row, and a glowing serif "have a project in mind?" contact block. Five photos + Prata/Inter (11 woff2) bundled locally. Dark-and-magenta serif portfolio, unlike any neighbour.
- New template: Forge — high-energy site for gyms, fitness studios, and strength coaches. Black and white with a single electric-lime accent; condensed Bebas Neue display over Urbanist for a real gym-poster voice. A dark hero pairs a giant "Train hard. Get strong." headline (lime emphasis) and dual CTAs with a grayscale equipment photo behind a lime square. Sections: a full electric-lime stats band (24/7, equipment, members, coaches), a dark six-card coached-programs grid (strength, HIIT, boxing, mobility, cardio, 1-on-1), a soft why-us split with a numbered list and a lime "12 years" badge, a dark three-up trainer grid with grayscale-to-colour hover, three membership tiers with a featured black plan, and a full electric-lime "your first rep starts today" CTA. Five photos + Bebas Neue/Urbanist (4 woff2) bundled locally. Black-and-electric-lime condensed energy, unlike any neighbour.
- New template: Solara — clean, optimistic site for solar installers, renewable-energy companies, and green-tech firms. White with pale-green section tints, a fresh eco-green accent, and deep dark-forest bands; bold Inter type. The hero pairs a "power your home with the sun" headline and a trust row with a pure-CSS savings-estimate card — labelled sliders (monthly bill, roof space) feeding a highlighted "$41,800 over 25 years" result and a quote CTA. Sections: a dark stats band (MW installed, homes powered, CO₂ saved), a four-card solutions grid (panels, storage, EV charging, maintenance), a pale-green about split with a green "12 yr" badge and a checklist, a four-step "how it works" process, a three-tile projects gallery with category labels, and a green "cut your bills" CTA. Four photos + Inter (7 woff2) bundled locally. Eco-green-and-forest with a savings-calculator motif, distinct from the green charity neighbour.
- New template: Brio — loud personal-portfolio site for freelance designers, creatives, and solo studios. White, black, and a single crimson-red accent; heavy Inter throughout. The hero is a giant outlined name ("REMY.") with a red-stroked dot, an "award-winning freelancer" pill, a role line, and a short intro with dual CTAs, followed by a red scrolling skill marquee. Sections: an about split with a red-shadowed portrait and a three-stat row, a dark numbered services list (brand identity, web, art direction, packaging) that expands on hover, a two-up works grid with hover-zoom and red category chips, a centered client testimonial, and a full-red "let's make something good" contact block. Five photos + Inter (7 woff2) bundled locally. Red-and-black giant-type portfolio, unlike any neighbour.
- New template: Sterling — premium site for wealth advisors, financial planners, and investment firms. White and warm-paper with a bronze-gold accent and deep dark-slate bands; Jost wide-caps type throughout (with a bronze italic emphasis). Split hero pairs a "plan ahead" headline and a three-figure trust bar with a finance-desk photo framed by a bronze square and a dark-slate "+11.4% portfolio growth" card. Sections: a six-cell bordered expertise grid (wealth planning, investment, tax, retirement, estate, business owners), a dark-slate "by the numbers" band with animated score bars (94/96/98%) and a four-stat strip, an approach split with a numbered four-step process, three anonymised result cases with big figures, a centered client testimonial, and a dark-slate "book a consultation" CTA. Two photos + Jost (3 woff2) bundled locally. Bronze-and-slate wealth palette, distinct from the run's brighter neighbours.
- New template: Maven — loud, confident fashion e-commerce for clothing labels, boutiques, and streetwear brands. White and near-black with a single pure bright-yellow accent; heavy uppercase Outfit display (with an outlined text-stroke headline word) over Figtree. A dark promo bar tops a split lookbook hero with a yellow season tag, a model photo, and a rotated yellow "-30%" badge, followed by a black-bordered yellow scrolling marquee. Sections: a three-tile shop-by-category grid with hover-zoom and gradient overlays, a four-up new-arrivals product grid with sale flags, hover "add to bag", and struck-through prices, a full-bleed black mid-season sale band with a yellow highlight, a wide editorial/journal feature card, a four-icon promises row, a yellow "10% off" newsletter, and a four-column dark footer. Ten fashion photos + Outfit/Figtree (4 woff2) bundled locally. Pure-yellow-on-black commerce energy — distinct from the quiet mono clothing neighbour and the run's lighter yellows.
- New template: Lumio — bright online-course and e-learning platform for course creators, academies, and bootcamps. White with pale-mint section bands, dark teal-charcoal ink, an acid-lime accent and a warm-orange pop; Space Grotesk headlines over Inter. Hero pairs a lime-highlighted headline ("Learn the skills that get you hired") with a course search bar, enrolment stats, and a learner photo carrying a floating "certificate earned" chip and a course-progress card. Sections: a six-tile category grid with course counts, a three-card popular-courses grid (level tag, duration, instructor avatar, rating, price), a dark "why Lumio" band with four lime-iconed benefit cards, a full lime stats strip, and a mint "first course free" CTA. Four photos + Space Grotesk/Inter (10 woff2) bundled locally. Lime-and-mint course layout, distinct from the run's neighbours.
- New template: Everwell — warm, trustworthy site for senior-care homes, assisted-living communities, and home-care providers. Pale blue-gray section bands with deep-navy ink and a raspberry-rose accent; Rufina high-contrast serif headlines (with rose italic emphasis) paired with Be Vietnam Pro. Split hero with a "call anytime" phone in the nav, a caregiver photo framed by a rose circle and a floating "15+ years" card, plus a trust row. Sections: four floating feature cards (personal care / on-site health / daily activity / family updates), a six-card services grid (assisted living, memory care, respite, skilled nursing, wellness, home visits), an "our hospitality" about split with a navy "98% recommend" badge and a checklist, three transparent care-plan pricing tiers (Companion / Residential / Memory Care) with a highlighted middle plan, a four-item FAQ accordion, two family testimonials, and a navy "book a visit" CTA. Two care photos + Rufina/Be Vietnam Pro (16 woff2) bundled locally. Navy-and-rose healthcare palette, unlike any neighbour.
- New template: Folio — author and single-book landing page for writers, ebook authors, and small presses. White canvas with pale-blue and pale-lavender section bands, dark-gray ink, and a mustard-gold accent; Marcellus uppercase serif paired with Karla. The hero splits a big serif title ("The Shape of Ideas") against a pure-CSS 3D book cover (no cover image needed — rendered with spine, gold rule, and shadow). Sections: dark four-stat benefits band (awards / any device / audio / readers), an about split with a pull-quote and a 2×2 stat block, a twelve-chapter contents list with page numbers, an author bio with a portrait and signature, three reader reviews with star ratings, a buy-from-stores grid (Amazon / Apple Books / Bookshop / Direct) with bundle pricing, and a "free first chapter" email CTA. One author photo + Marcellus/Karla (4 woff2) bundled locally. Gold-on-white serif book layout, distinct from the run's agency neighbours.
- New template: Hyper — dark, high-energy site for creative digital agencies and brand studios. Charcoal canvas (#1A1916) with a single bright-yellow accent used as text highlight marks, Unbounded rounded-display headlines over Inter, and a statement hero ("We make brands move fast and look sharp.") with yellow
<mark> highlights. Sections: dark nav, the highlighted hero with a pill eyebrow and dual CTAs, a scrolling client wordmark marquee, a six-card services grid, a four-card case-study grid with photos, a yellow stats band, and a closing CTA + footer. Four work photos + Unbounded/Inter (12 woff2) bundled locally. The run's bright-yellow-on-dark palette sets it apart from the white/peach design-agency neighbour.
- New template: Stark — loud editorial site for brand & design studios and creative agencies. Stark white-and-near-black with a single warm-peach accent, ultra-bold Syne display in oversized uppercase, a hairline-ruled hero, and a dark scrolling services marquee. Seven sections: a giant typographic statement hero, the marquee, a 2-up grayscale-to-colour work grid, an inverted dark three-step process, three bordered review cards, and a full peach closing CTA. Four photos + Syne/Inter bundled locally. Big, all-caps, and confident — the opposite of the quiet mono fashion neighbour.
- New template: Hearth — refined homeware e-commerce for furniture, lighting, and decor studios. White canvas with deep-slate ink, soft pastel section tints (warm beige, pale cyan, pale blue), and a clay accent; light-weight Spectral serif with italic emphasis. Split hero on a beige panel, three room-category tiles, a four-up product grid with prices/materials, a pale-blue "our story" split, a four-icon benefits row, and a beige newsletter band. Nine photos + Spectral/Inter bundled locally. Warm, elegant, and serif-led — clearly apart from the stark mono fashion neighbour.
- New template: Quanta — bright analytics SaaS site for product-analytics, BI, and data tools. White canvas with dark-gray ink and a golden-yellow accent (used as highlight underlines and chart fills), Epilogue display, and a hero pairing a statement with a live CSS analytics dashboard (KPI tiles + a rising bar chart). Seven sections: dashboard hero, logo strip, six-feature grid, a use-cases split with a CSS funnel visual, a dark stats band, and a golden closing CTA. No photos — pure-CSS data UI. Epilogue + Inter bundled locally. Golden-yellow + charts set it apart from the emerald price-table crypto neighbour.
- New template: Helix — light fintech site for crypto exchanges, trading apps, and finance products. Light-gray canvas with near-black ink and an emerald accent (with red/green price chips), Familjen Grotesk display, and JetBrains Mono price tickers. The hero pairs an email-capture statement with a live "Live prices" coin card (BTC/ETH/SOL/USDC); a top-movers markets table, a six-card "why" grid, a three-step onboarding, and a dark trust band with security stats follow. No photos — all pure-CSS data UI, so it's fast and unmistakably a finance product. Familjen Grotesk + Inter + JetBrains Mono bundled locally.
- New template: Meridian — modern SaaS/corporate site for software platforms and B2B products. White canvas with deep regal-navy ink and a vivid flamingo→amethyst→green tri-gradient (plus a standalone green), Figtree display, and a hero pairing a bold statement with a cluster of gradient metric/rating cards (4.98 ★, teams onboarded, on-time bar). Seven sections: hero, logo strip, six-card platform grid, a navy impact band with gradient stats, three customer testimonials, and a gradient closing CTA. Three photos + Figtree/Inter bundled locally. The warm tri-gradient + navy keeps it clear of the cool blue-violet agency neighbour.
- New template: Atlas — warm corporate site for growth consultancies, advisory firms, and B2B services. White canvas with a deep-charcoal and burnt-orange palette, Schibsted Grotesk display, a top announcement bar, and a split hero (text + office photo) with a charcoal "$340M raised" badge. Seven sections: hero, four-up stats, four icon service rows, an inverted charcoal three-step approach, three flexible engagement tiers, a two-column FAQ, and an orange closing CTA. One photo + Schibsted Grotesk/Inter bundled locally. Burnt-orange-and-charcoal sets it firmly apart from the indigo corporate neighbour.
- New template: Frequency — high-energy site for conferences, summits, and ticketed events. Deep midnight-blue canvas with vivid coral and electric-cyan accents, ultra-bold Archivo display, soft colour glows, and an event-specific countdown hero (day/hour/minute/second tiles). Eight sections: countdown hero, three "why attend" cards, a four-up speaker grid, a main-stage agenda list, three ticket tiers (with a featured "best value"), a sponsors strip, and a coral gradient closing CTA. Four speaker photos + Archivo/Inter bundled locally. The run's first dark template — distinct from the white/pastel neighbours by palette and the countdown motif.
- New template: Norden — minimal editorial e-commerce for clothing labels, boutiques, and fashion shops. Near-monochrome palette (white, near-black, cool gray) where the product photography supplies all the colour, refined Jost display with wide letter-spaced caps, a centered wordmark nav with cart, and a top promo bar. Full-bleed lookbook hero with overlay, three full-height category tiles, a four-up product grid with prices/sale tags and hover "add to bag", a split editorial journal block, a four-icon promise row, and a dark newsletter band. Nine photos + Jost/Inter bundled locally. Gallery-quiet — the first template with no vivid accent colour, by design.
- New template: Kindred — warm, hopeful site for foundations, charities, and non-profits. Racing-green and goldenrod-yellow gradient palette with zircon-gray bands, characterful Bricolage Grotesque display paired with Mulish, rounded buttons, and a donation-progress motif throughout. Split hero (text + community photo) anchored by a live "this month" funding-goal card with a gradient progress bar; deep-green stats band; three open-cause cards each with their own funding %; a four-step "where your gift goes" how-it-works; a mission split; a dark-green three-up "ways to help"; and a gradient donate panel. All five photos + Bricolage Grotesque/Mulish bundled locally.
- New template: Keystone — buttoned-up corporate site for management consultancies, advisory firms, and B2B services. White canvas with a solid indigo accent (no gradient) and light blue-gray section bands, Plus Jakarta Sans bold headlines, and a split hero (text left, office photo right) anchored by a dark floating "200+" stat card. Eight sections: hero, four-up stats band, four service boxes, an inverted dark "how we work" capabilities split with a numbered list, three anonymised results cards with big figures, a two-column FAQ, and an indigo contact card. Two photos + Plus Jakarta Sans/Inter bundled locally. Solid and corporate — distinct from the agency neighbour's gradient playfulness.
- New template: Sherbet — soft, playful creative-studio site for designers, agencies, and small brand shops. Seashell & misty-rose pastel canvas with a bright-turquoise accent and a coral pop, light-weight Sora display (300) with blurred colour blobs, rounded pill buttons, and a centered airy hero over a wide rounded studio photo. Eight sections including three colour-coded service cards, a numbered approach list beside a portrait, a 3-up rounded work grid, a client wordmark strip, three colour-blocked testimonial cards, and a full turquoise contact card. All eight photos + Sora/Inter bundled locally — soft and bright, the opposite of the bold white/grotesk neighbour.
- New template: Voltage — bold branding & digital studio site. Pure-white canvas with near-black ink and a vivid electric blue→violet gradient accent (plus a fuel-yellow pop), oversized Space Grotesk grotesk headlines with tight negative tracking, and a soft gradient orb behind the hero. Nine sections: statement hero with a four-stat bar, client wordmark strip, six service cards with line icons, an inverted dark four-phase Process band, a 2-up Work grid, a full-bleed gradient Results band, three client voices, and a rounded dark contact card. All seven photos + 16 woff2 (Space Grotesk + Inter + JetBrains Mono) bundled locally. Deliberately the inverse of the warm-cream/serif look — white, electric, geometric.
- New template: Longhand — editorial Sunday-newsletter template for writers, journalists, and solo publishers. Warm-paper background with ink-black headlines and a single sun-yellow accent, Newsreader transitional serif (italic-capable) paired with Hanken Grotesk, and a newspaper-masthead hero (italic serif title centered + meta strip above + featured-letter preview card below — no hero photo). Nine sections: dark meta-strip nav, masthead hero with this-week feature, three-up latest letters with images, drop-cap About-the-writer, eleven-chip Topics strip, full dark Essay block with pull-quote, free Newsletter signup form, ten-row Archive index, and a dark Footer. All four photos and sixteen woff2 files bundled locally.
- New template: Maison Lune — refined beauty studio template for salons, spas, and skin clinics. Soft pearl-pink and deep mauve palette with dusty-rose serif italic accents, Playfair Display Didone serif paired with Manrope humanist sans, and a photo-LEFT + text-RIGHT hero where the hero portrait sits in an arched-top soft-rectangle frame with a peach decorative circle bleeding behind the headline. Seven sections — six-treatment menu cards with prices, centered manifesto with French quote marks, four-specialist grid with morphing arched portrait frames, mosaic look-book, three-up dark voices block, and a dual-column Visit panel with arched studio photo. Bilingual touches throughout (French/Portuguese flavour). All eleven photos and twenty woff2 files (Playfair Display + Manrope + JetBrains Mono) bundled locally.
- New template: Hollis (replaces Bellweather & Sons) — heritage barbershop template with a condensed-display voice. Deep-forest-green ink on warm cream with brass-honey accents, Oswald condensed display throughout (heavy uppercase), and an asymmetric three-photo collage hero crowned by a rotated brass "Est. 2017" circular stamp. Seven sections — eight-line menu with stand-alone prices, mosaic gallery grid, four-barber profile cards on dark inverted panel, three reviews, a dual-column Visit panel, and a dark booking CTA. The previous Bellweather & Sons template (cream + Bodoni Moda + teal serif italic) has been archived to
references/old site builder templates/bellweather/ for posterity. All thirteen photos and 18 woff2 files (Oswald + Inter + JetBrains Mono) bundled locally.
- New template: Plinth — editorial brutalist site for architecture practices, studios, and design firms. Slate-concrete and bone with a burnt-sienna serif italic accent, Fraunces variable display serif paired with IBM Plex Sans, and a full-bleed hero photo with overlay typography (no split, no centered). Eight sections including a 4-up Selected Work grid, an inverted dark Practice/manifesto block with pull-quote, a four-partner Studio grid with desaturated portraits, a five-row "What we make" services list, a chip-strip of recognition/press, and a brick-and-mortar Visit panel. All ten photos and 22 woff2 files (Fraunces + IBM Plex Sans + IBM Plex Mono) bundled locally.
- New template: Stride — calm SaaS landing for software products and small-team tools. Stark white with a black ink and an electric-mint accent, geometric DM Sans throughout, and a stacked hero (no photo) that pairs a giant typographic headline with a custom CSS-rendered "Today" workspace mockup below — checklist, task statuses, owner avatars, all painted in pure HTML/CSS. Ten sections including a CSS-rendered check-in mockup, three-tier pricing (Solo / Team / Studio), an integrations chip strip, and a black FAQ panel with mint accents. No reveal JS; works offline; all fonts (DM Sans + JetBrains Mono) and three customer portraits bundled locally.
- New template: Ledger & Stone — confident editorial site for boutique CPA practices, financial advisors, and tax firms. Deep-navy ink on cream paper with a warm champagne-brass italic accent, structural Roboto Slab display type, and a fully typographic centered hero (no photo) crowned by a four-figure stats bar. Ten sections — Services (six lines), Approach (drop-cap manifesto), Partners (four CPAs), Process (four steps), Pricing (three fixed-fee tiers), Cases (three anonymised wins), FAQ, and a navy contact panel. All fonts (Roboto Slab + Inter + JetBrains Mono) and four partner portraits bundled locally; every nav link and CTA resolves to a real section anchor.
[2026-05-21]
- New template: Stillpoint — a warm-sunset editorial site for yoga and meditation studios. Cream parchment background, coral italic accents on the serif headline ("A quiet hour, three times a week."), single hero photo with sunset gradient bleed, and ten in-page sections — Practice (6 class types), Philosophy manifesto, four senior Teachers, Weekly Schedule table, three-tier Memberships, Visit/Studio details, Testimonials, and a first-class-free CTA. Cormorant Garamond + Inter + JetBrains Mono bundled; 6 imagery references local in
media/. Every nav link and button anchors to a real section id — no dead links.
[2026-05-20]
- New template: Meridian Racing — high-octane motorsports site for race teams, riders, and event organizers. Black background with sodium-yellow signal accent and race-red highlights, oversized condensed Antonio display font ("Built Fast. Ridden Faster. Round 09."), full-bleed bike hero. Antonio + Archivo + JetBrains Mono bundled; 7 imagery references (6 unique photos) local.
- Refined the Adex hero. The headline was overscaled (max 156px) — brought it down to a more elegant 96px max, restructured from three lines to two (
Paid growth, / without the [↗] guesswork.), refined the inline accent pill, and added a row of metric tag chips (CPA · ROAS · LTV/CAC · Incrementality · MMM) under the side description for visual balance. Hero now feels editorial instead of shouty.
[2026-05-19]
- New template: Alex Reyna — dark editorial portfolio for creative directors and brand strategists. Black background with cream serif headlines and an amber accent, magazine-style "Issue Nº" header, full-bleed portrait, recognition strip. DM Serif Display + Manrope bundled; 8 imagery references local.
- New template: Annie Park — clean, terminal-flavored portfolio for freelance engineers and indie developers. Off-white background with a violet italic accent on the hero word,
whoami prompt eyebrow, founder-tools strip across the bottom. Fraunces + Space Grotesk bundled; 10 imagery references local.
- New template: Autofix — bold, no-nonsense site for independent auto repair shops. Dark workshop background with bright orange CTAs, oversized "Honest repair / Fair price / Done right" hero, services + ASE-certified team block. Archivo + Archivo Narrow bundled; 8 imagery references local.
- New template: Bellweather & Sons — classic editorial barbershop site with hot-towel-shave heritage charm. Cream background with deep teal serif italic ("since 1962"), decorative dividers, services + gallery + barbers + reviews. Bodoni Moda + Cormorant Garamond + DM Sans bundled; 16 imagery references local.
[2026-05-18]
- Template gallery reset to a clean slate. Cleared 72 of the 76 shipped templates to make room for a new generation. Only Boldy, Boldgen, Finner, and Leadgen remain as base templates; the retired set is preserved offline for reference, not visible in the gallery.
- New template: Adex — a dark, performance-marketing studio layout with serif headlines, an electric-lime accent, and a live KPI ticker across the hero. Ships fully self-contained: fonts (Instrument Serif, Space Grotesk, JetBrains Mono) and all imagery are bundled inside the template folder, so sites built from it work offline and on custom domains without external CDN dependencies.
- New template: Albert Mori — a warm, editorial portfolio for independent designers and consultants. Newsreader serif headlines with italic emphasis, muted terracotta accents on a cream background, portrait hero with floating studio badge. All fonts (Newsreader, Hanken Grotesk, JetBrains Mono) and 11 imagery references bundled locally for evergreen, CDN-independent sites.
[2026-05-16]
- Pancho app iframes auto-fit in published sites. When you embed a donation form (Donately) or gallery (GalleryHub) on a sitebuilder page using the
?embed=1 URL, the iframe now resizes to match the form/gallery content — no more empty space below or inner scrollbar. Works automatically on publish; just re-publish your site to pick it up.
[2026-05-14]
- Added a Watch/Read tab on the tutorial page — every lesson now has a written version alongside the video for users who prefer to read.
[2026-05-09]
Internal
- Custom-domain integration is now declarative. Site Builder used to be hardcoded into the customdomains extension as the only app that could route a domain to a per-entity URL (a published site). That special case has been replaced with a generic contract: any app can now declare a
custom_domains.subtargets block in its app.json and a list_handler callable, and the customdomains UI will show the second "pick which one" dropdown automatically. Site Builder's mapping (each domain → a specific published site) is preserved end-to-end — verified domains keep working, the static-file fast path is unchanged, and the picker UI looks identical. The only user-visible difference: the picker label is now driven by Site Builder's app.json instead of being hardcoded "Pick which site".
- The "Saved!" dialog after changing a site address is now in plain language with clickable links. Replaced the previous "PANCHO ADDRESS (ALWAYS WORKS) / The old address has stopped working" text — none of which was meaningful to non-technical users — with a clean receipt: "You can visit your site at:" followed by the actual URL as a green clickable link, plus a one-click Copy button. If a custom domain is connected, that's shown as the primary URL and the platform URL drops to a soft "Another way to reach your site:". If the site isn't published yet, the dialog says "When you publish, your site will be at:" so the user knows the new URL only goes live after they hit Publish. Both URLs open in a new tab when clicked, no jargon.
- Site addresses now display their full URL (e.g.
https://mypancho.com/p/.../site/my-cool-site/) in the change-address dialog instead of a partial path like /site/my-cool-site. Custom-domain URLs are surfaced first when a domain is mapped at /account/domains so the tenant sees what their customers will actually see, not the platform fallback.
[2026-05-08]
- You can now change a site's URL. The default URL slug used to be locked to whatever you (or the template) named the site at creation time — so a site you started as "Untitled" stayed at
/site/untitled-site-xxxx/ even after you renamed it. Open the site name pill in the editor → Change site address to pick a new slug. The old URL stops working immediately, the new one takes effect on the next request, and any custom domain pointed at the site keeps working — its mapping updates automatically. Validation: lowercase letters, numbers, and dashes only; 3–80 characters; must be unique among your own sites.
- My Sites cards show the actual site, not the original template screenshot. Each save scans the draft's home page for a real image and caches its path on the site record, so the dashboard thumbnail follows along as you swap out hero photos. If the page has no image yet, the original template screenshot stays as a fallback. The line under the time on each card now shows the site's web address (e.g.
/site/my-cool-site) instead of the template name — the address is now editable per-site, so it's actually useful information.
- Friendlier "Change site address" dialog with a clear confirmation receipt. Replaced the technical wording (URL, 404, custom domain) with plain language. After saving, a follow-up dialog shows the new address in a copy-friendly code block so you know it stuck.
- Fixed a save-path bug that created phantom
app/sitebuilder/drafts/{siteId}/ folders inside drafts. When VvvebJS sent a save call using the asset URL form (/app/sitebuilder/drafts/{siteId}/media/foo.jpg), the path sanitizer stripped only the leading / and the bare drafts/{id}/ prefix — not the URL prefix. The result was a nested duplicate directory tree inside the draft. Sanitizer now also strips the URL prefix before resolving the on-disk path. Existing zombie folders are safe to delete from FTP; the actual site files at the top of the draft are untouched.
[2026-05-02]
- Email-based "Forgot your PIN?" reset is live (platform feature, not just Site Builder). Users with an email on file can now reset their PIN from the login page without contacting support and without spending an SMS. Flow: click "Forgot your PIN?" on
/login → /reset-pin page → enter email → 6-digit code emailed via PHP mail() (Virtualmin/Postfix) → enter code + new 4–6 digit PIN → automatically signed in. New views: core/views/desktop/reset-pin.php and core/views/mobile/reset-pin.php, both with a two-step JS state machine, resend-code cooldown (30s), shake-on-error inputs, and a "Didn't sign up with an email? Call us" fallback. New route /reset-pin in core/index.php. Most of the backend was already built — users.email column with case-insensitive unique index, pin_reset_code + pin_reset_expires_at columns, mail_pin_reset_code() template, send_mail() transport, IP rate limits (10 requests/hr, 20 verifies/hr), privacy-preserving "if that email is on file…" responses — they just had no UI. Also fixed a pre-existing dead-code bug: two case 'request-pin-reset': switches in the auth dispatcher (legacy phone-based and new email-based) made the email handler unreachable. Removed the unused phone-based request-pin-reset and reset-pin cases since nothing in the codebase called them. Smoke-tested end-to-end via curl: unknown email returns the same generic success ("If that email is on file…"), bad code is rejected (E_RESET_INVALID), bad email format rejected, and the happy path clears the reset code, hashes the new PIN, increments login_count, and starts a session.
[2026-05-02]
- Stripped back the media-library overrides — round 2. Previous attempt to switch the list to a vertical flex stack also broke the layout: 300×118 cards were getting forced into a single tall column, the hover-preview popover was positioned outside the modal, and action buttons overlapped the file name. The original media.css uses
display: inline-block; width: 300px; height: 118px cards floating side-by-side — that layout works fine, it just has the wrong colors. Reverted to a minimal cosmetic overlay that only changes background / border / text colors / focus rings on .filemanager .data li, plus quiets the bright Bootstrap btn-outline-primary / btn-outline-danger action buttons. Zero touches to display, position, width, height, or any layout property.
[2026-05-02]
- Fixed media-library thumbnail overlap. The previous facelift forced
ul.data into a CSS grid with cards (grid-template-columns: repeat(auto-fill, minmax(120px, 1fr))), but VvvebJS structures every <li class="files"> as a horizontal row containing an icon, name + size, action buttons, and a hover-only preview popover. The grid override smashed all those inline children into the same cell, so the row icon + the hover-preview's image rendered on top of each other. Reverted to the original list-style layout (vertical stack, one row per file), kept only the cosmetic dark theme — row background, accent-green selected state, themed action icons (rename / delete / zoom-preview), small 36×36 thumbnail at the left, name + details on a single line, dark preview popover. No structural changes; just CSS that respects the markup it's styling.
[2026-05-02]
- Fixed broken side panel — Templates / Pages / Elements / Stock tabs were not clickable. Last change introduced a JS syntax error:
console.warn('… VvvebJS didn\\'t clear it'). I escaped the apostrophe with a double backslash (PHP HEREDOC convention I'd been using elsewhere), but _editor-core.html is a plain HTML file — JS sees \\' as an escaped backslash followed by a string-terminator quote, breaks parsing of the rest of the script (SyntaxError: missing ) after argument list), and every IIFE after that point dies — including the tab click handlers. Fixed by dropping the apostrophe and using "did not" in the log message. Audited the rest of _editor-core.html for the same bug — every other apostrophe escape in there was already correct (\' produced from PHP HEREDOC \\' is valid JS).
[2026-05-02]
- Fixed canvas spinner stuck after creating a new page. The previous safety net that hid VvvebJS\'s
loading-message overlay only ran ONCE — at initial editor boot. So when a user created a new page mid-session, the iframe started loading the new draft URL, and if VvvebJS\'s init chain hit any snag in _frameLoaded (or just took its time waiting on Bootstrap\'s CDN to finish loading inside the iframe), the spinner stayed visible forever. New behaviour: a MutationObserver watches the canvas iframe\'s src attribute and re-arms a 5-second safety net every time it changes, plus an explicit iframe.load listener clears the spinner ~600ms after each load fires regardless of what VvvebJS does internally. Console logs a warning ([SB] loading-message safety net fired) when the safety net actually has to do anything, so we know if there\'s a real bug to chase. Initial-boot safety stays at 6 seconds.
- Confirmed: upload-project saves files in the correct user folder. Verified that the existing path resolution (
sb_user_root($userId) → users/{uuid}/sitebuilder/drafts/{siteId}/) is what upload-project.php uses, and the static-passthrough route serves those exact paths back. No path leakage possible — the realpath check at write time refuses any file that ends up outside realpath($draftRoot).
- Moved the "view page" arrow icon out from under the demo countdown badge. When a user had a long site name (e.g. "Ironwood-Lock-and-Key"), the platform\'s demo banner overlapped the site-indicator group and hid the external-link icon next to it — making it impossible to click "open the page in a new tab". Moved the icon out of the site-indicator group and into the action-buttons group on the right (immediately before the Publish button) where there\'s no overlap with the demo banner regardless of site name length.
- VvvebJS Media library facelift. The built-in image picker (clicked when you want to swap an image\'s source) was Bootstrap-default light theme — bright blue "Browse Files" button, white modal, etc. — totally clashing with the editor\'s dark theme. Cosmetic-only refresh: dark gradient modal surface, accent-green dashed drop zone with a halo icon, accent-green primary buttons (Browse Files, Add Selected) with the same gradient as our other primary CTAs, dark cards in the file grid with accent border on hover/selected, accent-green focus ring on the search input, dark footer. Every rule scoped to
body.sb-editor #MediaModal ... so it can\'t leak into other Bootstrap modals on the page. Zero markup or JS changes — drop the CSS block to revert.
- Fixed two upload-flow bugs that left users stuck after a successful upload:
- Editor was showing the "Welcome — what would you like to build today?" overlay on top of the uploaded site. The welcome overlay only hides when
sites.template is non-empty, and the upload was creating sites with template = NULL (correct in the literal sense — there's no template), so the editor treated each upload like a fresh blank canvas. Fix: upload now writes template = '_uploaded' (underscore-prefix sentinel that can't collide with a real template id) so the welcome overlay stays hidden and the user lands directly on their imported site, ready to edit.
- Auto-redirect to the new site's editor was unreliable. Browsers can block programmatic top-window navigation triggered by an XHR callback (no user-gesture context), and the modal had no visible escape hatch when the redirect quietly failed. Replaced the silent redirect with a success card that swaps in after upload: green check-circle icon, "Got it — your site is ready to edit", a big primary "Open {site name} in the editor" button (real
<a target="_top"> so it always works as a user-clicked navigation), and a small "Stay here for now" link. The card still attempts auto-redirect 400ms after success, but the button is the source of truth — if browser policy or anything else blocks the auto-nav, the user has an obvious one-click next step that can't be blocked.
- Upload modal — non-technical copy + actionable error messages. First-cut version was full of jargon ("HTML file or ZIP archive — saved as the index of a new site... extracted into the new site\'s draft folder"). Rewrote everything for a small-business owner who hired a designer and just wants to bring their site in:
- Title: "Open a website you already have"
- Subtitle: "Already got a site from a designer, an old export, or somewhere else? Bring it here and edit it just like one of our templates."
- Drop zone: "Drop your website file here / or click anywhere in this box to pick one / Web page (.html) or zipped folder (.zip) — up to 25 MB"
- How this works (numbered): "Pick your file" → "We open it for you" → "Publish when you\'re ready", each with one sentence of plain English.
Also fixed the drop zone being left-aligned within the modal — the <label> was inline by default; now it\'s display: block; width: 100%; box-sizing: border-box so it fills the card.
- **Every upload error now explains why and *what to do next*** instead of dumping a one-line technical message. Each rejection comes back as a
{ title, hint } pair the modal renders as two lines (red title + lighter actionable hint). Examples:
- PHP code in HTML → "We can\'t accept this file because it has server code in it. / Your page contains PHP code (the bit that starts with
<?php). For security, we only accept regular web pages. Open the file in a text editor, remove the <?php blocks, and try again."
- Executable in ZIP → "There\'s a program file in your ZIP that we can\'t accept: shell.php / For security, we only accept content files (HTML, CSS, JavaScript, images, fonts, videos). Files like .php are program code that runs on the server and could be unsafe to host. Remove that file from the folder and re-zip."
- Missing index.html → "Your ZIP doesn\'t have an index.html file. / Every website needs a home page called index.html. Make sure that file exists in your folder (or one folder deep) and re-zip. If the file is named differently — like home.html or main.html — rename it to index.html first."
- Path traversal, hidden files, server-config files (.htaccess / .env / web.config), zip-bomb size caps, too-many-files, file > 10 MB, total > 50 MB, corrupted ZIP, network failure, server save failure — all now spell out the user-actionable fix. Same goes for client-side rejections (wrong extension, > 25 MB) before the upload even starts. New
SBUploadError class carries title + hint cleanly through the catch block.
[2026-05-01]
- Upload an existing site as a new project. New cloud-arrow icon in the toolbar (right next to the Properties gear) opens a drag-and-drop modal where you can upload a single HTML file or a ZIP archive of a static site. The upload becomes a brand-new site in your library with the original filename as the site name; the editor reloads onto the new site as soon as the upload completes. Security: 25 MB upload cap, extension whitelist (.html / .htm / .zip), and a strict ZIP entry walk that rejects path traversal, executable file types (.php / .phtml / .phar / .exe / .sh / .bat / .cgi / .pl / .py / .asp / .jsp / .dll / etc.), server-config files (.htaccess / .htpasswd / .env / web.config / php.ini), hidden dot-folders (.git / .ssh), per-file size > 10 MB, total uncompressed > 50 MB (zip-bomb defence), or > 1000 entries. Every HTML file (top-level OR inside the ZIP) goes through
sb_sanitize_html() to drop any embedded PHP. If index.html is buried inside a single subfolder of the ZIP, that folder is treated as the site root. Final realpath check on every written file confirms it actually lives inside the user's draft folder. Smoke-tested end-to-end: HTML, ZIP, embedded PHP shell rejected, path traversal rejected, executable extension rejected, missing index.html rejected.
- Stock tab cleanup. Removed the category chip strip (Trending / Wallpapers / 3D Renders / Nature / etc.) — the search bar and image/video toggle alone are enough; the chips ate vertical space and added a fiddly horizontal scrollbar. Search and the Images/Videos toggle now sit on a single row, and the toggle is icon-only (
🖼 / 🎬) so the search field gets the full remaining width. Cards reach further down the panel.
- Properties panel facelift + always-visible gear. Two small polish passes:
- The Properties (gear) toolbar button is now visible from page load instead of hiding until the first element click. Less surprising for users who already know they want to edit something.
- Gave the Properties panel a cosmetic refresh to match the rest of the editor's dark theme. Content / Style / Advanced tabs use our muted-uppercase typography with an accent-green underline on the active one. The "No selected element!" empty-state alert is now a dark card instead of Bootstrap's default warning yellow. Section headers (LINK / GENERAL / DIMENSIONS / etc.) match the small uppercase metadata style we use elsewhere. Form inputs (text, select, range, color, checkboxes) all use the dark
--sb-card surface with an accent-green focus ring. Custom dropdown chevron on <select> so it matches our other panels. Scrollbar styling tightened to thin grey on transparent. Every rule is scoped to body.sb-editor #left-panel #right-panel ... so it only affects the relocated panel — no chance of leaking into other panels or the canvas. No structural HTML changes, no component-handler changes; if anything looks broken, dropping just this CSS block reverts cleanly.
- Properties panel actually appears now when you click an element or the toolbar gear. The previous attempt repositioned
#right-panel over the left-panel area via CSS position: fixed; left: 0 — but VvvebJS's editor.css has many hardcoded rules on #right-panel (right: 0, float: right, width tied to --builder-right-panel-width, gradient backgrounds, box shadows) that fought my overrides and left the panel either invisible or rendered with zero width. Switched to a cleaner approach: physically move #right-panel into #left-panel on boot so it sits as a sibling of .pages-pane / .tpl-pane / .notes-pane, then style it to fill the panel area normally (position: static; flex: 1; width: auto). Show/hide follows the exact same body[data-sb-tab="properties"] pattern as every other tab pane — no fighting position: fixed, no z-index issues. VvvebJS still finds the panel by ID, so its auto-populate-on-selectNode behavior keeps working untouched.
- Properties / Notes panel: stop the Pages tree from leaking through. Switching to the Properties or Notes view used to show the new pane PLUS the Pages tree (Index / assets / etc.) underneath it, because the rule that hides VvvebJS's
#filemanager only listed the Pages, Templates, Elements, and Stock tabs — not the new Notes/Properties tabs. Added them to the hide list, then moved the same rule into editor.php's inline inject so we don't have to wait for the user's 24h editor.css cache to expire to see the fix. Also added a ?v={mtime} cache-buster to the editor.css link so future CSS edits roll out immediately on next reload instead of being held by the browser.
- Multi-page editing actually works now. Creating a new page from the editor's "+" button used to leave you with a 0-byte file and a Firefox "Can't Open This Page" error in the canvas iframe. Two bugs:
- VvvebJS's new-page form set
data.url to a bare filename like "about.html". The iframe's src resolved that against the parent's <base href="/app/sitebuilder/editor-assets/">, so the iframe tried to load /app/sitebuilder/editor-assets/about.html?... — which doesn't exist, so the route 404'd with the platform's default X-Frame-Options: DENY and Firefox blocked it. Patched Vvveb.FileManager.addPage to rewrite any non-absolute data.url to the full /app/sitebuilder/drafts/{siteId}/... path.
- The save endpoint wrote 0 bytes when VvvebJS submitted with
startTemplateUrl=new-page-blank-template.html and no html field (its convention for "seed this new page from a template"). Now apps/sitebuilder/api/drafts.php detects that case and writes a minimal HTML skeleton (<!doctype html> + bootstrap link + empty body) using the user's chosen page title. Existing files are protected — duplicate names return HTTP 409. Parent directories are auto-created so nested pages like blog/post.html work too.
Saving an already-existing page (the normal save path) is unchanged.
- Notes + Properties moved from the left tab strip to the top toolbar. The left strip was getting crowded; "STOCK" was sitting almost on top of the canvas. Notes and Properties are no longer 5th/6th tabs — they're toolbar buttons (sticky-note + gear icons) right next to "Toggle left column". The matching panes still render in the left-panel area when activated; only the trigger moved up. Each toolbar button toggles its mode on/off (clicking again returns you to whatever tab you were on before), shows an "active" pressed state when its pane is open, and the Properties button stays hidden until the user first clicks an element on the canvas.
- Notes save now shows visible feedback. Previously the save was silent — no way to tell if a note was actually saved. Now each note card flashes a small accent-green "Saving…" badge during the round-trip, switches to a "Saved ✓" badge with a green border-tint flash on success, then fades after ~1.6s. On failure, a red "Couldn't save" badge stays put + a toast surfaces the error. Skips the round-trip entirely when the textarea content hasn't actually changed since the last load.
- Notes are back — multi-note edition. The old Site Builder had a single-textarea-per-site notes feature stored over FTP. Brought it back as a proper multi-note scratchpad: a Notes tab in the editor's left tab strip (sticky-note icon, between Stock and Properties) where you can keep as many notes as you want about a site — bullet lists of TODOs, draft copy, color hex codes, design references, anything. Each note is its own card stacked newest-first, auto-saves on blur, shows an "Updated 3:42pm" timestamp, and has a small Delete button. Empty notes auto-delete to keep things tidy. New
site_notes table in the per-user app DB scoped per site (so each site's notes follow the site, not the user account). Server endpoints: GET /api/sitebuilder/notes/list?site_id=, POST create / update / delete. CSRF enforced; ownership joined through sites.created_by_user_id on every write so notes can't be guessed across users.
- Properties moved to a left-side tab — no more squished canvas. Earlier today the element-properties panel lived on the right side and was either always-visible (squishing the canvas, ugly divider, scrollbar) or auto-toggling (which annoyed users since they rarely click empty space to dismiss it). The right side is now retired entirely. New behaviour: a 5th icon-only Properties tab (gear glyph) appears in the left tab strip the first time the user clicks an element on the canvas, and auto-activates. Pages / Templates / Elements / Stock stay one click away — switching tabs no longer "closes" properties; it's just a tab. Implementation:
#right-panel is now positioned fixed over the left-panel area below the tab strip, only visible when body[data-sb-tab="properties"], and the right-side slot stays at 0 width so the canvas always gets the full remaining width. Removed the now-redundant "Toggle right column" toolbar button.
- Slimmer header. The top toolbar dropped from 56px to 44px to match the original Site Builder. Publish + Save Page were chunky two-line buttons that crowded the bar — they're now sized to match the My sites pill (5px×12px padding, 12.5px font, single line). Toolbar icon-only buttons (toggle file mgr, undo/redo, etc.) tightened to 4px×8px so the slimmer header doesn't crop them. Left-panel + canvas top offsets adjusted from 56 → 44px to match.
- Right properties panel now auto-shows / auto-hides instead of staying open all the time. Previously default-open, which squished the canvas and showed an ugly divider + scrollbar during regular template browsing. Now the panel stays closed until the user clicks an element on the canvas — then it slides in with that element's Content / Style / Advanced tabs — and slides back out when nothing is selected. Hooked by wrapping
Vvveb.Builder.selectNode() (the single chokepoint VvvebJS uses for both click-on-canvas and programmatic selection) so the auto-toggle fires consistently in every selection path. Manual toggle via the toolbar's right-column button is honored as a sticky session preference: once the user clicks it, the auto-behavior backs off so it doesn't fight them. Body/html selections (which VvvebJS does internally for coarse focus changes) are filtered out so the panel doesn't flicker on every canvas click.
- Removed the bundled "AI assistant" button that VvvebJS auto-injected into the inline element toolbar (the wand-icon action that showed a tooltip "AI assistant"). It was wired to a feature we don't ship and just confused users when they clicked an element. Done by commenting out
<script src="libs/builder/plugin-ai-assistant.js"> in _editor-core.html. The plugin file itself is left in the vendored libs folder so future VvvebJS upgrades don't break the diff. No other code referenced it.
- Element properties panel now opens by default on the right. Clicking an element on the canvas already populated the right-panel's Content / Style / Advanced tabs (this is a built-in VvvebJS feature) — but the panel was being closed on init via
Vvveb.Gui.toggleRightColumn(false), so users had to discover the toolbar's "Toggle right column" button before they could edit anything. With our custom 4-tab left panel (Pages / Templates / Elements / Stock) covering up VvvebJS's old in-left-panel Properties tab, users had no way to reach element editing on click. Fix: dropped the init-time toggleRightColumn(false) and pre-flipped the toolbar toggle's active / aria-pressed="true" state so the button reads "on" from the start.
- Stock swap — slot dimensions are now actually preserved. The previous "preserve dimensions" pass copied
width/height HTML attributes onto the new node, but most templates style images via CSS (width: 100%; height: auto on a flexbox child) — so swapping a square 800x800 image for a portrait 4000x6000 stock photo let the new image's natural intrinsic ratio take over and the slot reflowed to portrait. Real fix: before swapping src, measure the old element's rendered getBoundingClientRect() and pin the box's shape with inline aspect-ratio + object-fit: cover (also width/height in px and max-width: none). The new image fills the same visual slot at the same shape, content cropped to fit, and the surrounding layout doesn't move a pixel. Same logic applied to the cross-kind path (image ↔ video). Idempotent — won't override styles the author already set explicitly.
- Stock swap now preserves the original's dimensions and styling. When you replace an image (or swap an image for a video) on the canvas, the new media now inherits every attribute of the one it replaces —
width, height, class, inline style, id, anything else — so a 4000x6000 stock photo dropping into a styled hero slot keeps the slot's dimensions instead of blowing up to natural resolution and breaking the layout. Same-kind swap was already in-place (so it kept everything by definition); the cross-kind path (img ↔ video) now copies attributes onto the new node before replaceWith(). The only attributes deliberately NOT copied are the ones that came from the new media (src, srcset, poster, alt) and the temporary highlight marker the drag-target outline used.
- Stock tab — second pass of fixes after the first user test:
- Click on a stock card now actually replaces a selected image instead of silently dropping nothing. Previously, when an image element was selected on the canvas, the code did
selectedEl.appendChild(node) — but <img> is a void element and can't have children, so the insert silently failed. Rewrote the placement logic: if you have an existing image or video selected, clicking a same-kind stock card swaps the src (and alt/srcset) in place — so all the surrounding wrapper classes, sizing, and layout stay intact. Mixing types (image → video or vice versa) does a replaceWith(). Clicking on a non-media element drops the new node after it as a sibling so it lands beside what you pointed at instead of getting buried in the child list. Empty-canvas behaviour (append to body) is unchanged.
- Drag-and-drop now tracks the actual drop target. Dragging a stock card over an existing image and releasing now replaces it. Added an iframe-body
dragover listener that records the element directly under the cursor, paints a 2px dashed accent-green outline on it as a drop indicator, and passes that target into the same swap/replace path as click. Drop on a section / div → new media is appended next to it. Drop on empty canvas → still appends to body. The outline is cleared on dragleave (when leaving the iframe entirely) and on dragend.
- Stock pane now fills the panel. The Pages tree (Index / content / css / js / …) was visible underneath the Stock pane because the
#filemanager hide-rule in editor.css only listed templates and elements — not the new stock tab. Added stock to that selector so the tree is hidden in stock mode, and changed .stock-pane from height: 100% to flex: 1; min-height: 0 so it fills the remaining vertical space the same way .tpl-pane does. Cards now fill the whole panel from search bar to the bottom Pexels attribution line.
- Tab labels no longer jammed against the canvas edge. With four tabs (Pages / Templates / Elements / Stock) sharing the same panel width that three used to, "STOCK" was sitting right on the right edge of the left panel. Tightened the tab typography: font-size 12 → 11, letter-spacing .04em → .02em, horizontal padding 14 → 8, gap 6 → 5. Now every tab has comfortable breathing room and "STOCK" doesn't look like it's about to run into the canvas.
- Stock tab — three first-day fixes:
- Cards no longer overlap each other. The grid was using
aspect-ratio: 4/3 on .stock-card with <img height: 100%> inside. Some browsers/contexts let the natural intrinsic image height win over the box's aspect ratio (especially with portrait video thumbnails), pushing each card taller than 4:3 and bleeding the bottom of one card under the top of the next. Switched to the bulletproof padding-top: 75%; height: 0 box and absolute-positioned the <img> / <video> over it with width: 100% !important; height: 100% !important; object-fit: cover. Now every card is a clean 4:3 tile that crops the image, with zero vertical bleed regardless of the source media's natural aspect ratio.
- Click-to-insert now also dismisses the welcome overlay. When the canvas was empty, the "Welcome — what would you like to build today?" card was covering the canvas, so clicking a Stock card silently inserted the image behind the welcome card. The toast said "Image added to canvas" but the user saw nothing change. The insert flow now calls
window.SB_DISMISS_WELCOME() (the editor's existing dismiss helper) before appending so the inserted image is the first thing the user sees on the now-revealed canvas.
- Closed the active-tab underline bleed. The accent-green underline beneath the active tab appeared to extend into the canvas area on some renders. Added
overflow: hidden to .pt-tabs and to the panel surface in stock-tab mode so nothing in the tab strip can paint past the right edge of the left panel.
- Added a Stock tab to the editor — browse free Pexels photos and videos right from the canvas. No more leaving the editor, finding a photo elsewhere, uploading it, then coming back. The new fourth tab on the left panel (Pages | Templates | Elements | Stock) opens a dedicated stock-media browser:
- Search at the top — type "ocean", "team meeting", "neon sign" — debounced 300ms so each keystroke isn't a request.
- Images / Videos toggle pills — flip between photos and short video loops.
- Category chips — Trending (default), Wallpapers, 3D Renders, Nature, Architecture, Minimal, Business, Technology, People. Click a chip to swap the current query.
- Two-column grid of thumbnails with the photographer credit visible on hover and a small "Video" badge on video cards.
- Click a card to insert the full-resolution image (or
<video controls>) into the canvas — drops at your current cursor position if you have something selected, otherwise at the bottom of the page. Triggers VvvebJS's undo/save cascade so it's part of the next save.
- Drag a card onto the canvas — same insertion path, native HTML5 drag.
- Load more button at the bottom for paginated browsing — preserves what's already loaded so you don't lose your place.
- Photographer attribution is shown on every card and links back to their Pexels profile, satisfying the Pexels TOS the old stock page didn't comply with.
- The Pexels API key never reaches the browser. Requests go through a new
/app/sitebuilder/api/stock/{search|curated} server proxy that adds the auth header on the server, normalizes the response shape, and applies a 5-minute private cache to keep us under Pexels' rate limit. The old Site Builder hardcoded the key client-side; we don't repeat that.
- Simplified the publish flow. Hitting Publish in the editor used to pop a "Publish your latest changes?" confirmation dialog before doing anything — an unnecessary speed bump for a non-destructive action (the button itself is the confirmation). It now goes straight to publishing: the button shows a spinner + "Publishing…" while the API call runs, and when it succeeds you get a beautifully styled success card instead of the old "You're live! 🎉" sheet. The new card has a clean accent-green check-circle icon (no emoji), a soft radial halo behind it, the title "Site published", a one-line body, and two buttons: Continue editing (ghost style) closes the card; Open in new tab opens the live URL in a new window. No site URL text is shown — the button does the work, and the URL itself is noise the user doesn't need to read out. Backdrop and Esc both close the card.
- Fixed three billing-page bugs after upgrade:
- "Next charge on Apr 30, 2026" showed the LAST day of the current cycle instead of the actual charge date.
current_period_end is stored as the last second of the cycle (e.g. 2026-04-30 23:59:59); Pancho bills on the 1st of every month, so the real next-charge date is +1 day. Added a dedicated format_plan_next_charge_date() helper that does the +24h shift, and switched the desktop + mobile billing views from format_plan_period_end() to it. Now reads "Next charge on May 1, 2026".
- "Free trials" section + "Site Builder · 0m left · Upgrade" still showed up on the billing page after a user upgraded to Premium. Belt: the section is now hidden when
plan.status='active' && plan.plan_id!='free' && !plan.paused_at. Braces: the actual fix is in /api/plan/upgrade — on successful upgrade, all of the user's demo / expired / cancelled install rows for premium apps are promoted to type='premium', status='active' in a single UPDATE, so has_app_access() and the marketplace card stop treating them as expired demos. Backfilled in place for the 1 already-upgraded user who was caught between releases.
- "Upgrade to Premium" header showed even when the user was already on Premium (the page below correctly read "You're on Premium" — the header just contradicted it). Now the header switches to "Your Premium plan" / "You're already on Premium — every app's unlocked." when
$isPaidPlan. Same fix applied on mobile (header → "Your plan").
- Cleaned up stale
app_installs rows where type='free' but the app had since been promoted to tier='premium' — Site Builder rows for two seeded users still claimed type='free' from before the tier change, which would have caused weird mismatches between the install record and the apps table. Updated 2 affected rows in place (type='free' → 'premium') and updated [seed.php](seed.php) so freshly-reset databases create the rows correctly going forward.
- Toned down the Premium label on the App Marketplace cards. Was a loud accent-colored heading at 18px / weight 800 — same size as the "Free" price next to it — which made every premium card scream "Premium" louder than the app name. Now it's a subtle uppercase metadata chip (11px, muted text color, 1px border, soft secondary background), reading like a tier tag rather than a price. Same restyle applied on mobile.
- Added a 4-demo cap on the platform's "Try Free" flow. Previously a user could restart the same app's demo as many times as they wanted (or end the demo, which also wiped the count, allowing infinite resets). Now
app_installs.demo_count (new column) increments on every demo start, and case 'demo': in extensions/billing/api/apps.php rejects the 5th attempt with HTTP 402 + a friendly message: "You've already used your 4 free demos for {app}. Upgrade to Premium to keep using it." The cap is configurable via the platform-wide demo_max_attempts setting (defaults to 4). The end-demo action now sets status='expired' instead of deleting the row, so the count survives between demo cycles. Verified end-to-end with the dev server: attempts 1–4 return 200 + redirect to the app, attempt 5 returns 402 with code: 'E_DEMO_LIMIT_REACHED' and redirect: /upgrade?app=…&reason=demo_limit.
- I tested the user's "Try Free taking me to upgrade" report end-to-end and the demo-restart API actually works fine — both attempts after force-expiry returned
success: true and /app/sitebuilder loaded. Most likely the user clicked the Upgrade to use button next to "Try Free" by mistake (both render side-by-side after expiry). Worth a future UX pass to make Try Free more visually distinct.
- The My Sites page now lays out 5 cards per row at desktop widths (was a
minmax(280px, 1fr) auto-fill that capped at 4 with a 1280px max-width). Drops to 4 columns under 1500px, 3 under 1180px, 2 under 860px, and a single column on phones — so the grid stays comfortable at every breakpoint without ever clipping a card mid-thumbnail.
- The My Sites page now opens with the platform sidebar collapsed by default, matching the editor's behaviour. You can still expand it any time with the sidebar toggle. Bouncing between My Sites and the editor no longer makes the sidebar flicker open and shut.
- Removed the dark-mode toggle from the editor's top toolbar — the editor is dark-themed by design and the toggle didn't visibly do anything for users. One less mystery icon at the top.
- Tightened the active-tab background on the four icon tabs (Sections / Components / Properties / Styles) at the top of the Elements panel — the soft accent-tinted square was too tall + too wide; reduced padding from
8px 12px to 4px 8px and dropped the corner radius from 8 to 6 so the tint hugs the icon instead of looking like a giant button.
- Removed the three-dots menu from the cards on the My Sites page entirely — clicking a card now just opens it in the editor (which is what almost everyone wanted to do anyway). Site management moved into the editor itself.
- Made the editor's site-name pill a real site-options menu. Click it (top right of the toolbar) to get a clean dropdown with Rename, Duplicate, and Delete site. Each one hits the same
/api/sites/rename / /duplicate / /delete endpoints the dashboard used to use, so behaviour is identical: rename updates in place, duplicate copies the draft and opens the new copy, delete confirms then drops you back at the dashboard. The menu auto-closes on outside click or Esc and is right-aligned under the pill so it can't blow past the iframe edge.
- Fixed the three-dots menu on the My Sites page. Clicking the three dots on a site card now opens the action sheet (Open in editor / Rename / Duplicate / Delete site) instead of doing nothing — an old
event.stopPropagation() on the menu button was blocking the card-level click handler from running.
- Added inline rename to the editor toolbar. The site name shown at the top right is now a clickable pill ("🌐 My site name ✎") — click it to rename the site without leaving the editor. Saves via the same
/api/sites/rename endpoint the dashboard uses, and the displayed name updates instantly without a page reload.
- Removed the duplicate "Site Indicator" + "Site Management cog" pair in the editor's top toolbar — they both opened the same flyout. Replaced with the single click-to-rename pill above. The Site Management flyout itself stays in the markup (Clone / Change Domain / Delete / Notes are still wired) but is no longer reachable from the toolbar; rename — by far the most common action — is now one click instead of three.
- Polished the Elements panel with a real cosmetic facelift to match the rest of the dark editor theme. Top icon tabs (Sections / Components / Properties / Styles) now use rounded pill buttons with a soft accent-tinted active state and an accent-green icon highlight; Sections / Page Sections sub-tabs use a clean accent-green underline; the search input grew to a 34px tap target with the dark form style and accent focus ring; the +/- zoom controls match the panel surface; the "All Design Styles" select now has a custom dark chevron icon in place of the default OS triangle; the category accordions (Hero, Essentials, Features, …) get a subtle accent-tinted background when open and a soft hover highlight; section thumbnail tiles now lift on hover with an accent border + shadow + grab cursor, and their captions use the editor's display + monospace fonts. All cosmetic — zero changes to the underlying VvvebJS markup, click handlers, or drag-and-drop behaviour. Scoped tightly to
body[data-sb-tab="elements"] so nothing leaks into other tabs.
[2026-04-30]
- Owner-aware caching on published sites. The published-site routes (
/p/{uuid}/sitebuilder/site/… and custom domains) now choose the Cache-Control header based on who's viewing: the site owner gets no-store, no-cache, must-revalidate, max-age=0 for every file type — HTML, images, video, everything — so a freshly published change shows up the moment they refresh the live URL. Visitors get normal caching: HTML revalidates on every request (public, no-cache, must-revalidate), CSS/JS cache for 1 hour, images/fonts/video cache for 1 day. Owner detection is via $_SESSION['user_id'] matching the URL's owner UUID (or the custom domain's user_id row), so the same user account hitting the site from a logged-in tab gets fresh content while every other visitor on the planet gets a fast cache. Also strips PHP's auto-emitted Pragma/Expires headers from session_start so they don't conflict with the explicit Cache-Control. Replaces the previous flat 5-minute cache that confused owners during the rapid edit-publish-refresh loop.
- Replaced the editor's custom upgrade modal with the platform's core upgrade sheet. The Site Builder was hardcoding "Upgrade to Premium / Premium turns on publishing, custom domains, and priority support across every Pancho app / $9.99 / month" — but the actual price is whatever's configured in the platform's plan config, NOT $9.99. The custom modal also reimplemented the no-card-on-file capture flow and the charge step, duplicating logic the platform's
PS.requestUpgrade() already does correctly. Now sbStartUpgradeFlow() is a 6-line wrapper that calls top.PS.requestUpgrade({ planId: 'premium', returnAppId: 'sitebuilder', onSuccess: …}) — the platform fetches the live plan name + price from /api/plan/request-upgrade, opens its standard sheet in the top window (consistent across every Pancho app), handles the no-card flow, and calls back our onSuccess to flip SB.isPremium and re-trigger the publish. Net change: 60 lines deleted, 23 added.
- Exposed
PS as window.PS in core/assets/js/app.js. Top-level const PS = {…} creates a lexical binding only — window.PS was undefined, so child iframes (like the Site Builder editor running inside the platform shell) couldn't reach back via top.PS. Added window.PS = PS; at the bottom of the file. Existing in-page callers are unaffected (they reference PS.toast(…) etc. by lexical name).
- Found and fixed the real "Use this design" bug (and the matching "Upgrade to publish" bug). Both buttons share the same modal component (
.sb-modal-wrap), and both were doing nothing for users — but a programmatic puppeteer click DID succeed. Root cause: a CSS specificity inversion in editor.css. The base rule was body.sb-editor .sb-modal-wrap, .sb-modal-wrap { opacity: 0 } (specificity 0,2,1,0), and the activation rule was .sb-modal-wrap.show { opacity: 1 } (specificity 0,2,0,0). The base rule WINS, so adding the .show class never made the modal visible — it stayed at opacity: 0 despite being display: flex with z-index: 99999 and a full-viewport rect. The modal was technically clickable through the DOM (which is why programmatic tests passed), but invisible to humans. Removed the redundant body.sb-editor qualifier from the base rule so the .show rule now wins by source order.
- Fixed Use this design — the apply API was working perfectly server-side (verified end-to-end with curl: POST /templates/apply returns
{"success":true} and the template files land in the user's draft folder), so the bug had to be in the post-success page reload. Switched the reload from window.location.reload() (reloads only the inner editor iframe) to target.location.href = '/app/sitebuilder/editor?site=…' on the top window. Some browsers refuse to reload a same-origin iframe from inside it without a fresh user gesture in nested-iframe contexts, which is why the old reload silently no-op'd. Hitting the top window with an explicit URL navigation always works. Same fix applied to startFromBlank when it does need to wipe an existing template.
- Smarter Start from blank: if the canvas is already empty (the site has never had a template applied), the button skips the "are you sure?" modal entirely and routes the user straight to the Elements tab with a brief panel pulse + "Blank canvas ready — drag a section from Elements" toast. Only when there's an actual template to wipe does the confirmation prompt appear; after confirming, the editor reloads and lands on the Elements tab automatically (we set a
sb-open-elements-{siteId} sessionStorage flag before reload, and the editor consumes it on the next paint).
- The welcome card's Start from blank button reuses the same flow, so clicking it on a fresh site now visibly switches the panel to Elements (with a pulse) instead of "doing nothing" because the canvas was already blank behind the welcome.
- Fixed the editor hanging at load (round 2). The previous round's empty-canvas card had two root elements (
<style>html,body{…}</style> plus the placeholder <div>). The injection logic uses template.content.firstElementChild — so only the <style> was actually being inserted, the EMPTY_ID div was lost, and the MutationObserver kept re-firing because the placeholder it expected to find was never there. The observer kept appending <style> tags forever, locking the main thread (Chrome's "Page is busy" dialog). Removed the standalone style tag — the placeholder div now covers the full viewport via position: fixed; top:0; left:0; right:0; bottom:0 with its own dark gradient, which gives the same visual result without the second root element.
- Fixed the editor hanging at load. Root cause was the dev-mode error toast I added a few iterations back — its
document.body.appendChild(el) call ran synchronously, but the script lives in <head> so document.body was still null early in the load. That made the toast itself throw, which fired window.onerror again, which re-entered the toast, which threw, looping forever and freezing the page. The error handler now defers DOM access until DOMContentLoaded, wraps every step in try/catch, and never throws back into the handler.
- Reverted the "Use this design" + "Start from blank" flows to a simple API succeeds →
window.location.reload() pattern. The clever in-place iframe-swap was fighting nested-iframe quirks and adding bugs without obvious upside; a single editor-frame reload after the apply API call lands you back on the freshly applied template every time. (Confirmation modal stays — only the "after confirm" plumbing was simplified.) The custom canvas loading-overlay helpers (sbShowApplyOverlay / sbHideApplyOverlay) are no longer needed and were removed.
- Fixed a white strip at the bottom of the empty canvas. The placeholder card was sized with
min-height: 90vh, which left a 10% gap at the bottom showing the iframe's default white body. Switched the card to position: fixed; inset: 0 and seeded the canvas iframe's <html><body> with background: #0b0d10 so the dark surface covers the entire canvas, edge to edge.
- Beefed up the "Use this design" confirm modal: it's now styled visible at append-time (
opacity: 1 inline, no rAF dependency) and every interaction is logged — modal-opened (with computed opacity / display / rect), backdrop click, Cancel click, OK click, Escape press, and final close-with-value. If the apply still feels like nothing happens, the console will tell us exactly which event fired (or didn't) instead of guessing.
- Polished the empty-canvas placeholder card. The wording was misleading ("Open the Sections or Components panel" — those panel names don't exist anymore) — it now reads "Open the Elements tab on the left and drag a section onto the page", which matches the actual UI. The card itself was also a bright-white slab in the middle of an otherwise dark editor; it's now styled to match: dark panel surface with the editor's accent-green icon tile, soft accent gradients on the canvas background, and the same monospace "drag & drop to build" caption used elsewhere.
- Cleaned up the Describe-your-site form. The currency dropdown now sits beside the "Or type your own industry" input on the same row (2:1 grid) instead of taking a full row of its own. The whole Save draft / Load draft / "Draft saved a moment ago" auto-save pipeline is gone — generating a prompt is fast enough that drafts were just clutter; you fill it in, hit Generate, copy the result, done. The Open Claude button has been replaced with a Share button that uses the OS native share sheet when available and falls back to copy-to-clipboard everywhere else, so the prompt isn't tied to one specific AI vendor.
- Added a
console.log trace to sbConfirmApply so when a template Use modal opens, the console now records "[SB] sbConfirmApply: opening modal for {id}" plus the modal's bounding rect — if the modal is rendering off-screen or its rect is zero, that's now visible.
- Reordered the Elements tab section list so Hero is first, with Essentials right after — the order now reads Hero → Essentials → Features → Payments → Forms → About → Team → Testimonials → Gallery → Counter → Step Box → Pricing → Call To Action → FAQ → Footer.
- Gave the Elements tab a small dark-theme facelift to match the rest of the editor: panel and accordion backgrounds use the editor's
--sb-panel ink, the sub-tab indicator switches from default Bootstrap blue to the editor's accent green, search and select inputs use the dark form style with the matching focus ring, and section item cards pick up the accent border on hover. All scoped to body[data-sb-tab="elements"] so the underlying VvvebJS markup is untouched.
- Added a dev-mode error toast: any uncaught JS error or unhandled promise rejection now pops a red banner at the bottom of the editor with the exact error message and the file/line. Replaces the silent failures that had us guessing why "nothing happens" — if "Use this design" still does nothing, the toast will show the actual reason.
- Fixed the "Toggle left column" toolbar button — clicking it once would hide the left panel, and a second click did nothing because our
--builder-left-panel-width override used !important, which made VvvebJS's togglePanel() always read the original computed value (420px) and re-enter the "hide" branch. Removed !important (the source-order cascade is enough), so toggle now hides on first click and restores on second.
- Restored the Sections and Components panel as a third "Elements" tab in the left panel, alongside Pages and Templates. Click the new Elements tab to drag any of VvvebJS's pre-built sections, blocks, and components onto the canvas. Previously the panel was hidden entirely by a
display: none !important override left over from the original Cloud Design mockup.
- Renamed the templates URL to the simpler
/app/sitebuilder/templates/{id}/… and dropped the legacy /templates-asset/… alias entirely (per dev-mode policy: no fallbacks).
- Removed the silent 6-second safety timeouts from the apply / start-from-blank flows. If the canvas iframe doesn't fire its
load event the loading overlay now stays up so you SEE the problem instead of having it papered over. Apply errors (no template found, API failure, missing iframe element) now pop a red alert modal with the exact reason instead of silently returning.
- Hardened the "Use this design" template-apply flow. The canvas iframe is now navigated by a direct
iframe.src = … assignment instead of via VvvebJS's loadUrl() helper (which had an if (iframe.src != url) guard that could edge-case no-op and leave the canvas showing the old template). Same hardening applied to the Start-from-blank flow.
- Silenced the
unload is not allowed in this document console violation by emitting Permissions-Policy: unload=(self) on the editor responses, so VvvebJS's iframe-navigation tracker registers cleanly.
- Renamed the templates URL from
/app/sitebuilder/templates-asset/{id}/… to the simpler /app/sitebuilder/templates/{id}/… — the old -asset suffix only existed to avoid a route collision that never actually applied. The legacy URL still routes to the same files for backwards compatibility, so any bookmarks keep working.
- Welcome screen buttons now actually do something visible when clicked. Browse templates dismisses the welcome card, scrolls the templates panel to the top, briefly pulses the panel with an accent ring, and pops a small "Pick a design from the panel on your left" toast — previously the templates panel was already visible behind the welcome, so the click felt like nothing happened. Start from blank now triggers the actual blank-canvas flow (with its confirmation prompt) instead of just dismissing the welcome card silently.
- The editor now opens inside the Pancho platform shell instead of taking over the whole window. The platform sidebar stays visible on the left (collapsed by default for maximum canvas room) so you can jump to Home, Apps, Billing, or any of your other Pancho apps without leaving the editor. Click the sidebar's expand toggle any time to see the full nav. Authoring still feels full-screen — the editor itself fills everything to the right of the (collapsed) sidebar.
- Removed the "Website Apps" button (and the slide-out panel it opened) from the editor's top toolbar — it pointed at an integration that wasn't being used and only added clutter.
- Replaced the Pancho logo in the editor's top-left corner with a clean "← My sites" back link, so there's an obvious one-click way out of the editor and back to the dashboard from anywhere in the canvas.
- Made the "Loading {template name}…" canvas overlay much more visible while a template is being applied — it now uses a solid backdrop instead of a barely-there transparent layer, so you can actually see something is happening during the swap.
- Polished the Describe-your-site form. Industry: the "Or type your own" box is always visible under the chips with its own helper label, so non-technical users don't have to guess where to type. Currency: now a compact, narrow dropdown instead of a full-width field — it's just a currency picker, not a hero. Social handles (Instagram, Facebook, X, TikTok, YouTube, LinkedIn): each input now shows the URL prefix (
facebook.com/, x.com/, etc.) as a fixed label inside the field, so users only type their handle / page name. Voice & tone: the three options are now full cards with one-line descriptions explaining when to pick each — no more guessing what "Bold" means.
- Fixed an issue where applying a template (or starting from a blank canvas) could leave the editor looking like it had frozen — the canvas now shows a tidy "{template name} is loading…" overlay that clears automatically when the new design is ready, with a 6-second safety net so it can never get stuck.
- Reworded the toolbar magic-wand tooltip and the in-editor overlay header so it's obvious the feature builds a prompt you paste into any AI, not a fully-built website. The tooltip now reads "Generate a prompt to build your site with AI" and the overlay reads "Generate a website prompt for AI" with a one-line subtitle.
- Fixed the editor's chrome alignment. The toolbar's Publish and Save Page buttons were being clipped at the bottom by the canvas, the templates panel had a thin gap above it, and the canvas itself was extending under the panel. All three were the same root cause — a CSS variable scope issue — and now the toolbar, panel, and canvas line up cleanly.
- Picking a template from the panel now shows a "Loading {template name}…" animation on the canvas while the new design is being applied. Previously the canvas just sat there during the swap.
- Moved "Describe your site" from a big button at the bottom of the templates panel to a small magic-wand icon in the editor's top toolbar (next to Preview, Fullscreen, Layers, Media). Hover for the tooltip; click to open the prompt generator over the canvas. Reclaims the space at the bottom of the templates panel for actual templates.
- Fixed the in-editor "Describe your site" overlay — it was failing to load with a "127.0.0.1 refused to connect" error because the platform's security policy was blocking iframes. Now the overlay loads the prompt generator correctly and fits exactly to the canvas area (no longer overlapping the templates panel on the left).
- Removed the standalone "Describe your site" entry from the app sidebar. The toolbar icon inside the editor is the single entry point.
[2026-04-29]
- Cleaned up the "My sites" page header. Dropped the breadcrumb line, the explanatory paragraph, and the status toolbar so the welcome heading "Hi {name}, what are we building today?" stands on its own. When you have sites, a small site count appears under the heading and the "New site" button stays in the top right.
- The empty "no sites yet" message is now a card the same size and shape as a real site tile, sitting in the grid with a soft accent gradient — no more giant centered panel below the page. Click the card to start your first site; once you have one, the card disappears.
- Renamed the "Prompt forge" feature to "Describe your site" — same magic prompt generator, but a name a non-technical user can act on. Moved it from the editor's top toolbar to a pinned button at the bottom of the templates panel.
- Clicking "Describe your site" inside the editor now opens the prompt builder right where the canvas is, instead of opening a separate page in a new tab. The Pages | Templates panel stays put on the left so you don't lose your place. Press Esc or "Back to editor" to return to the canvas.
- Removed the placeholder "Browse marketplace" and the disabled "Describe your site (coming soon)" links from the bottom of the templates panel — they were noise and there was no marketplace behind the link. Templates list now uses that vertical space for actual templates.
- Fixed the editor's top toolbar: the Publish and Save Page buttons were being clipped because the toolbar was too short. Bumped it to 56px so every button shows in full, and shifted the side panels and canvas down to match.
[2026-04-28]
- Publishing a site now requires an active premium plan. Free-plan users can still build, edit, and preview sites — when you press Publish, a one-tap upgrade sheet pops up so you can start Premium without leaving the editor.
- Added "Prompt forge" — a guided, one-page form that turns a few answers about your business (name, industry, sections you want, contact info) into a long, detailed prompt you can paste into Claude (claude.ai) to generate a complete one-page website. Pick from 20 ready-made section cards (hero, about, pricing, FAQ, gallery, booking form, map, social bar, and more), choose your tone, hit Generate, then click Open Claude. Drafts save automatically in your browser so you can come back to a half-filled form anytime.
- The generated prompt instructs Claude to build the site with inline-only styles and no shared rules — that way every element pastes into the Site Builder editor as its own independently editable piece.
- Added a "Prompt forge" button in the editor's top toolbar so you can jump from the editor straight to the prompt generator (opens in a new tab so your draft stays open).
- Fixed the editor's top toolbar — Publish, Save Page, and the new Prompt forge button no longer get clipped by the canvas underneath. The toolbar is now tall enough for full buttons and the panels and canvas shift down to match.
- Clicking "Start from blank" on the welcome screen now confirms with a small toast so it's clear the action took effect (previously the welcome dismissed silently and felt like nothing happened).
[2026-04-23]
- Site Builder is live. Drag-and-drop editor with 76 starter templates, multiple sites per account, and one-click publish.
- Added a beautiful Templates panel in the editor — browse, search, filter by category, and one click swaps your site to the chosen design.
- "My sites" dashboard shows all your sites with live thumbnails, status badges, and quick rename / duplicate / delete.
- Publish writes a clean static copy. Share it at a platform preview link or point your own domain at it.
- Opening the editor on a phone shows a friendly "use desktop" prompt with a "Continue anyway" option.
Internal
- Vendored the VvvebJS editor under
apps/sitebuilder/editor/ and bundled all 76 templates under apps/sitebuilder/templates/.
- New
sites table; new API surfaces for sites, drafts, uploads, templates, publish, and dynamic component loading.
- Added four static passthroughs in
core/index.php: /app/sitebuilder/editor-assets/, /app/sitebuilder/templates-asset/, owner-only /app/sitebuilder/drafts/, and public /p/{uuid}/sitebuilder/site/{slug}/.
- A fetch shim in the editor view retargets VvvebJS's hardcoded
save.php / upload.php / scan.php calls to the new platform endpoints and attaches CSRF + site id.
[2026-04-20]
- Demo and subscribe now work out of the box — finished migrating the app to Pancho's UUID identity model so Try Demo no longer errors with 'We could not start the demo'.
Internal
- Added the
tenant_members table to schema.sql (backed by the platform's _per_user_app_bootstrap_owner() hook).
[Baseline] — 2026-04-16
- Existing feature set captured as the baseline. Subsequent changes will be prepended above this entry.