diff --git a/craft/package.json b/craft/package.json index f73194d..5789f0c 100644 --- a/craft/package.json +++ b/craft/package.json @@ -11,6 +11,8 @@ "test:headed": "playwright test tests/site-builder.spec.ts --reporter=list --headed", "test:e2e:sitesmith": "playwright test tests/sitesmith.spec.ts --reporter=list", "test:unit": "vitest run", + "test:browser:bg": "node scripts/e2e-background.mjs", + "test:browser:canvas": "node scripts/e2e-canvas-parity.mjs", "test:unit:watch": "vitest" }, "dependencies": { diff --git a/craft/scripts/e2e-background-entry.tsx b/craft/scripts/e2e-background-entry.tsx new file mode 100644 index 0000000..441308d --- /dev/null +++ b/craft/scripts/e2e-background-entry.tsx @@ -0,0 +1,24 @@ +// Bundled by scripts/e2e-background.mjs and mounted in real Chromium. +import React from 'react'; +import { createRoot } from 'react-dom/client'; +import { Editor, Frame } from '@craftjs/core'; +import { HeroSimple } from '../src/components/sections/HeroSimple'; +import { BackgroundSection } from '../src/components/layout/BackgroundSection'; +import { CTASection } from '../src/components/sections/CTASection'; +import { CallToAction } from '../src/components/sections/CallToAction'; +import { Container } from '../src/components/layout/Container'; + +const resolver = { HeroSimple, BackgroundSection, CTASection, CallToAction, Container }; + +(window as any).mountNode = (id: string, type: string, props: Record) => { + const data = JSON.stringify({ + ROOT: { type: { resolvedName: 'Container' }, isCanvas: true, props: {}, displayName: 'Container', custom: {}, hidden: false, nodes: ['n'], linkedNodes: {} }, + n: { type: { resolvedName: type }, isCanvas: false, props, displayName: type, custom: {}, parent: 'ROOT', hidden: false, nodes: [], linkedNodes: {} }, + }); + const el = document.createElement('div'); + el.id = id; + document.body.appendChild(el); + createRoot(el).render( + , + ); +}; diff --git a/craft/scripts/e2e-background.mjs b/craft/scripts/e2e-background.mjs new file mode 100644 index 0000000..8366083 --- /dev/null +++ b/craft/scripts/e2e-background.mjs @@ -0,0 +1,63 @@ +#!/usr/bin/env node +/** + * Real-browser regression test: a `background` shorthand followed by an + * undefined/'' background longhand wipes the gradient in Chromium (React + * assigns '' for undefined style values). jsdom cannot reproduce this, so + * mount the real components via react-dom in headless Chromium and assert the + * COMPUTED style. Run: npm run test:browser:bg (needs a Playwright chromium) + */ +import { build } from 'esbuild'; +import { chromium, firefox } from '@playwright/test'; +import { fileURLToPath } from 'node:url'; +import path from 'node:path'; + +const root = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..'); +const out = await build({ + entryPoints: [path.join(root, 'scripts/e2e-background-entry.tsx')], + bundle: true, write: false, format: 'iife', platform: 'browser', + define: { 'process.env.NODE_ENV': '"production"' }, jsx: 'automatic', logLevel: 'error', +}); +const js = out.outputFiles[0].text; + +const cases = [ + ['hero gradient', 'HeroSimple', { bgType: 'gradient', bgGradientFrom: '#0f172a', bgGradientTo: '#334155' }, 'backgroundImage', /linear-gradient/], + ['hero color', 'HeroSimple', { bgType: 'color', bgColor: '#123456' }, 'backgroundColor', /rgb\(18, 52, 86\)/], + ['hero image', 'HeroSimple', { bgType: 'image', bgImage: 'https://example.invalid/a.jpg' }, 'backgroundImage', /url\(.*a\.jpg/], + ['hero video (fallback color)', 'HeroSimple', { bgType: 'video', bgVideo: 'v.mp4', bgColor: '#123456' }, 'backgroundColor', /rgb\(18, 52, 86\)/], + ['BackgroundSection image', 'BackgroundSection', { bgImage: 'https://example.invalid/b.jpg', bgColor: '#123456' }, 'backgroundImage', /url\(.*b\.jpg/], + ['BackgroundSection color', 'BackgroundSection', { bgColor: '#123456' }, 'backgroundColor', /rgb\(18, 52, 86\)/], + ['CTASection gradient', 'CTASection', { gradient: 'linear-gradient(135deg, #111111, #222222)' }, 'backgroundImage', /linear-gradient/], + ['CallToAction gradient', 'CallToAction', { bgType: 'gradient', bgValue: 'linear-gradient(135deg, #111111, #222222)' }, 'backgroundImage', /linear-gradient/], +]; + +// Override binaries with CHROMIUM_PATH / FIREFOX_PATH when the Playwright-pinned builds are not installed. +async function run(name, launcher, exe) { + const browser = await launcher.launch({ executablePath: exe || undefined, ...(name === 'chromium' ? { args: ['--no-sandbox'] } : {}) }); + const page = await browser.newPage(); + const errors = []; + page.on('pageerror', (e) => errors.push(String(e))); + await page.setContent(''); + await page.addScriptTag({ content: js }); + + let failed = 0; + for (const [i, [label, type, props, prop, re]] of cases.entries()) { + const id = `c${i}`; + await page.evaluate(([id, type, props]) => window.mountNode(id, type, props), [id, type, props]); + await page.waitForSelector(`#${id} section`, { timeout: 5000 }).catch(() => {}); + const value = await page.evaluate(([id, prop]) => { + const s = document.querySelector(`#${id} section`); + return s ? getComputedStyle(s)[prop] : '<>'; + }, [id, prop]); + const ok = re.test(value); + if (!ok) failed++; + console.log(`[${name}] ${ok ? 'PASS' : 'FAIL'} ${label}: computed ${prop} = ${value}`); + } + if (errors.length) console.log('page errors:', errors.join('\n')); + await browser.close(); + return failed; + +} +let total = 0; +total += await run('chromium', chromium, process.env.CHROMIUM_PATH); +total += await run('firefox', firefox, process.env.FIREFOX_PATH); +process.exit(total ? 1 : 0); diff --git a/craft/scripts/e2e-canvas-export-entry.ts b/craft/scripts/e2e-canvas-export-entry.ts new file mode 100644 index 0000000..bd2e65f --- /dev/null +++ b/craft/scripts/e2e-canvas-export-entry.ts @@ -0,0 +1,15 @@ +// Bundled (esbuild) by scripts/e2e-canvas-parity.mjs and run in Node: renders what a publish +// of the CURRENT stored state would emit, composed like TopBar's Preview +// (header + body + footer under the real document head). Used for specs whose +// checked-in published HTML is stale relative to the stored state. +import { exportBodyHtml, exportComposedPreviewHtml } from '../src/utils/html-export'; + +export function renderPublished(project: any, pageIdx: number): string { + const page = project.pages_craft_state[pageIdx]; + const hdr = project.header_craft_state ? exportBodyHtml(project.header_craft_state, 'header').html : ''; + const ftr = project.footer_craft_state ? exportBodyHtml(project.footer_craft_state, 'footer').html : ''; + const body = exportBodyHtml(page.craftState).html; + return exportComposedPreviewHtml(page.craftState, hdr + body + ftr, { + title: page.name, includeFonts: true, headCode: project.design?.headCode, design: project.design, + }); +} diff --git a/craft/scripts/e2e-canvas-parity.mjs b/craft/scripts/e2e-canvas-parity.mjs new file mode 100644 index 0000000..276d45c --- /dev/null +++ b/craft/scripts/e2e-canvas-parity.mjs @@ -0,0 +1,317 @@ +#!/usr/bin/env node +/** + * Real-browser regression test: the editor CANVAS must lay page content out + * exactly like the PUBLISHED page ("the site looks different in the builder + * than published"). jsdom has no layout, so this mounts the REAL editor (a + * vite build served by a tiny mock API) in headless Firefox AND Chromium, + * loads a stored project, and compares -- element by element -- against the + * same page's published HTML rendered in a plain page whose viewport equals + * the canvas content width. + * + * Stored state is loaded VERBATIM (blank style values included). Allowed editor-only + * differences (empty-container drop zone, empty-image placeholder) are neutralised in the + * canvas before measuring; see the ALLOWED block in run(). + * + * Compared per matched element: bounding box (x/y/w/h, within 1px) and the + * computed font-size / line-height / margin / padding / colour / font-family + * / font-weight / display. Editor-only chrome (the dashed header/footer zone + * separators) is compensated for, not ignored. + * + * npm run test:browser:canvas + * + * Env: + * CHROMIUM_PATH / FIREFOX_PATH override the Playwright-pinned binaries + * WHP_CANVAS_SPECS extra comma-separated spec.json paths + * (e.g. real customer sites kept out of git) + * CANVAS_SHOTS= write canvas + published PNGs there + * CANVAS_CHROME_DUMP= write a computed-style snapshot of the + * editor chrome (everything OUTSIDE the + * canvas frame) to diff before/after a change + * CANVAS_ONLY=chromium|firefox run a single browser + * + * A spec is {name, project: , published: {: }} + * with paths relative to the spec file. Only pages that have a published + * file are compared. + */ +import { chromium, firefox } from '@playwright/test'; +import { build as esbuild } from 'esbuild'; +import { execFileSync } from 'node:child_process'; +import http from 'node:http'; +import fs from 'node:fs'; +import os from 'node:os'; +import path from 'node:path'; +import { fileURLToPath } from 'node:url'; + +const root = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..'); +const VIEW_H = 1000; +const EDITOR_W = 1500; +const TOL = 1; // px + +// ---------------------------------------------------------------- specs +const specPaths = [ + path.join(root, 'tests/fixtures/canvas-parity/ols.spec.json'), + ...(process.env.WHP_CANVAS_SPECS || '').split(',').map((s) => s.trim()).filter(Boolean), +]; +// `published` is either {slug: html file} or "generate" = render what a publish of the stored +// state emits (scripts/e2e-canvas-export-entry.ts) -- for sites whose saved HTML is stale. +let renderPublished = null; +async function loadExporter() { + if (renderPublished) return renderPublished; + const out = await esbuild({ + entryPoints: [path.join(root, 'scripts/e2e-canvas-export-entry.ts')], + bundle: true, write: false, format: 'esm', platform: 'node', jsx: 'automatic', logLevel: 'error', + define: { 'process.env.NODE_ENV': '"production"', __EDITOR_BUILD__: '"test"' }, + banner: { js: "import { createRequire } from 'node:module'; const require = createRequire(import.meta.url);" }, + }); + const f = path.join(os.tmpdir(), `wsb-export-${process.pid}.mjs`); + fs.writeFileSync(f, out.outputFiles[0].text); + renderPublished = (await import(f)).renderPublished; + fs.rmSync(f, { force: true }); + return renderPublished; +} +const specs = []; +for (const p of specPaths) { + const dir = path.dirname(p); + const s = JSON.parse(fs.readFileSync(p, 'utf8')); + const project = JSON.parse(fs.readFileSync(path.resolve(dir, s.project), 'utf8')); + let published; + if (s.published === 'generate') { + const render = await loadExporter(); + const only = s.pages || project.pages_craft_state.map((pg) => pg.slug); + published = {}; + project.pages_craft_state.forEach((pg, i) => { if (only.includes(pg.slug)) published[pg.slug] = render(project, i); }); + } else { + published = Object.fromEntries(Object.entries(s.published).map(([k, v]) => [k, fs.readFileSync(path.resolve(dir, v), 'utf8')])); + } + specs.push({ name: s.name, project, published }); +} + +// NOTE: stored state is loaded VERBATIM, blank style values included (e.g. +// {padding:'20px', paddingTop:''} left by the style panel). The harness must test what +// the editor really renders; an earlier version stripped blanks and thereby hid a wipe bug. + +// ---------------------------------------------------------------- build + serve the real editor +const buildDir = fs.mkdtempSync(path.join(os.tmpdir(), 'wsb-canvas-')); +execFileSync(path.join(root, 'node_modules/.bin/vite'), ['build', '--outDir', buildDir, '--emptyOutDir', '--logLevel', 'error'], { cwd: root, stdio: 'inherit' }); + +let currentProject = null; +const mime = { '.js': 'text/javascript', '.css': 'text/css', '.html': 'text/html', '.png': 'image/png', '.svg': 'image/svg+xml' }; +const server = http.createServer((req, res) => { + const u = new URL(req.url, 'http://x'); + if (u.pathname === '/api/site-builder.php') { + res.setHeader('content-type', 'application/json'); + if (u.searchParams.get('action') === 'load') { + return res.end(JSON.stringify({ success: true, rev: 'r1', limits: {}, project: currentProject })); + } + return res.end(JSON.stringify({ success: true })); + } + const p = u.pathname === '/' ? '/index.html' : u.pathname; + if (p === '/index.html') { + const cfg = { user: 't', apiUrl: '/api/site-builder.php', csrfToken: 'x', siteId: 1, siteDomain: 'example.test', siteName: 'Parity', backUrl: '/', isRoot: false }; + const h = fs.readFileSync(path.join(buildDir, 'index.html'), 'utf8') + .replace('', () => ``); + res.setHeader('content-type', 'text/html'); + return res.end(h); + } + const f = path.join(buildDir, p); + if (f.startsWith(buildDir) && fs.existsSync(f) && fs.statSync(f).isFile()) { + res.setHeader('content-type', mime[path.extname(f)] || 'application/octet-stream'); + return res.end(fs.readFileSync(f)); + } + res.statusCode = 404; + res.end('nf'); +}); +await new Promise((r) => server.listen(0, '127.0.0.1', r)); +const base = `http://127.0.0.1:${server.address().port}`; + +// ---------------------------------------------------------------- in-page measurer (runs in BOTH documents) +function measure({ rootSel, isCanvas, skipNav }) { + const rootEl = document.querySelector(rootSel); + const rr = rootEl.getBoundingClientRect(); + const bl = isCanvas ? parseFloat(getComputedStyle(rootEl).borderLeftWidth) || 0 : 0; + const bt = isCanvas ? parseFloat(getComputedStyle(rootEl).borderTopWidth) || 0 : 0; + const ox = rr.left + bl; + const oy = rr.top + bt; + // Editor-only dashed zone separators shift everything after them by their width. + const zones = isCanvas ? [...rootEl.querySelectorAll('[data-zone-preview]')] : []; + const adjustY = (el) => { + let adj = 0; + for (const z of zones) { + const cs = getComputedStyle(z); + const zone = z.getAttribute('data-zone-preview'); + const bw = parseFloat(zone === 'header' ? cs.borderBottomWidth : cs.borderTopWidth) || 0; + if (zone === 'header' && !z.contains(el) && (z.compareDocumentPosition(el) & Node.DOCUMENT_POSITION_FOLLOWING)) adj += bw; + if (zone === 'footer' && (z === el || z.contains(el))) adj += bw; + } + return adj; + }; + const SKIP = new Set(['STYLE', 'SCRIPT', 'NOSCRIPT', 'LINK', 'META', 'BR', 'HEAD', 'TITLE', 'PATH', 'CIRCLE', 'RECT', 'LINE', 'POLYLINE', 'POLYGON', 'G', 'USE', 'DEFS']); + const norm = (s) => s.replace(/\s+/g, ''); + // Visible text only (never + + + + +
+ +
+

About OLS Digital

+

Who we are and what we believe in.

+
+
+

Our Story

OLS Digital was founded to bring structure, resources, and long-term support to promising digital brands. Rather than absorbing the businesses we work with, we help them keep their independent identity while benefiting from shared operational support.

Our Mission

We believe in honesty, quality, and putting people first. Every brand under the OLS Digital name is expected to uphold these same values in how they serve their customers.

+
+

Have Questions?

+

We'd love to hear from you.

+ +
+
+
© 2026 OLS Digital. All rights reserved. Questions? Email info@olsdigital.com
+ + \ No newline at end of file diff --git a/craft/tests/fixtures/canvas-parity/ols.brands.html b/craft/tests/fixtures/canvas-parity/ols.brands.html new file mode 100644 index 0000000..8ff1d64 --- /dev/null +++ b/craft/tests/fixtures/canvas-parity/ols.brands.html @@ -0,0 +1,54 @@ + + + + + + Brands + + + + + + + + + + + +
+ +
+

Our Brands

+

A closer look at the companies under the OLS Digital umbrella.

+
+
+
+

AnHonestHost

AnHonestHost provides transparent, no-nonsense web hosting for individuals and businesses. Straightforward pricing, honest support, and reliable infrastructure — no surprises.


+

StreamerTools

StreamerTools builds practical tools and resources for streamers and content creators, helping them grow their channels and streamline their workflow.

+
+

Interested in One of Our Brands?

+

Reach out and we'll point you in the right direction.

+ +
+
+
© 2026 OLS Digital. All rights reserved. Questions? Email info@olsdigital.com
+ + \ No newline at end of file diff --git a/craft/tests/fixtures/canvas-parity/ols.contact.html b/craft/tests/fixtures/canvas-parity/ols.contact.html new file mode 100644 index 0000000..fd32666 --- /dev/null +++ b/craft/tests/fixtures/canvas-parity/ols.contact.html @@ -0,0 +1,40 @@ + + + + + + Contact + + + + + + + + + + + +
+ +
+

Contact Us

+

Have a question about OLS Digital or one of our brands? We're happy to help.

+
+
+

Get In Touch

For all inquiries regarding OLS Digital, AnHonestHost, StreamerTools, or any of our other brands, please reach out via email and our team will respond as soon as possible.

info@olsdigital.com
+
© 2026 OLS Digital. All rights reserved. Questions? Email info@olsdigital.com
+ + \ No newline at end of file diff --git a/craft/tests/fixtures/canvas-parity/ols.index.html b/craft/tests/fixtures/canvas-parity/ols.index.html new file mode 100644 index 0000000..208d405 --- /dev/null +++ b/craft/tests/fixtures/canvas-parity/ols.index.html @@ -0,0 +1,64 @@ + + + + + + Home + + + + + + + + + + + +
+ +
+

OLS Digital

+

The parent company behind a growing family of trusted online brands, including AnHonestHost and StreamerTools.

+ +
+
+
+
+
🏢
+

Multi-Brand Portfolio

+

We own and support a growing collection of independent, high-quality brands.

+
+
+
🌐
+

AnHonestHost

+

Transparent, reliable web hosting built on trust.

+
+
+
🎮
+

StreamerTools

+

Tools and resources built for content creators and streamers.

+
+
+

Building Brands That Matter

OLS Digital is a privately held parent company focused on acquiring and growing digital-first businesses. Each brand under our umbrella operates independently, guided by a shared commitment to honesty, quality, and great customer experiences.

+
+

Want to Learn More?

+

For inquiries about OLS Digital or any of our brands, reach out to our team directly.

+ +
+
+
© 2026 OLS Digital. All rights reserved. Questions? Email info@olsdigital.com
+ + \ No newline at end of file diff --git a/craft/tests/fixtures/canvas-parity/ols.project.json b/craft/tests/fixtures/canvas-parity/ols.project.json new file mode 100644 index 0000000..4715075 --- /dev/null +++ b/craft/tests/fixtures/canvas-parity/ols.project.json @@ -0,0 +1,88 @@ +{ + "site_id": 100, + "name": "OneLastShot Digital", + "html": "
\n\n
\n

OLS Digital

\n

The parent company behind a growing family of trusted online brands, including AnHonestHost and StreamerTools.

\n \n
\n
\n
\n
\n
\ud83c\udfe2
\n

Multi-Brand Portfolio

\n

We own and support a growing collection of independent, high-quality brands.

\n
\n
\n
\ud83c\udf10
\n

AnHonestHost

\n

Transparent, reliable web hosting built on trust.

\n
\n
\n
\ud83c\udfae
\n

StreamerTools

\n

Tools and resources built for content creators and streamers.

\n
\n
\n

Building Brands That Matter

OLS Digital is a privately held parent company focused on acquiring and growing digital-first businesses. Each brand under our umbrella operates independently, guided by a shared commitment to honesty, quality, and great customer experiences.

\n
\n

Want to Learn More?

\n

For inquiries about OLS Digital or any of our brands, reach out to our team directly.

\n \n
\n
", + "css": "", + "pages": [ + { + "filename": "index.html", + "title": "Home", + "html": "
\n\n
\n

OLS Digital

\n

The parent company behind a growing family of trusted online brands, including AnHonestHost and StreamerTools.

\n \n
\n
\n
\n
\n
\ud83c\udfe2
\n

Multi-Brand Portfolio

\n

We own and support a growing collection of independent, high-quality brands.

\n
\n
\n
\ud83c\udf10
\n

AnHonestHost

\n

Transparent, reliable web hosting built on trust.

\n
\n
\n
\ud83c\udfae
\n

StreamerTools

\n

Tools and resources built for content creators and streamers.

\n
\n
\n

Building Brands That Matter

OLS Digital is a privately held parent company focused on acquiring and growing digital-first businesses. Each brand under our umbrella operates independently, guided by a shared commitment to honesty, quality, and great customer experiences.

\n
\n

Want to Learn More?

\n

For inquiries about OLS Digital or any of our brands, reach out to our team directly.

\n \n
\n
" + }, + { + "filename": "brands.html", + "title": "Brands", + "html": "
\n\n
\n

Our Brands

\n

A closer look at the companies under the OLS Digital umbrella.

\n
\n
\n
\n

AnHonestHost

AnHonestHost provides transparent, no-nonsense web hosting for individuals and businesses. Straightforward pricing, honest support, and reliable infrastructure \u2014 no surprises.


\n

StreamerTools

StreamerTools builds practical tools and resources for streamers and content creators, helping them grow their channels and streamline their workflow.

\n
\n

Interested in One of Our Brands?

\n

Reach out and we'll point you in the right direction.

\n \n
\n
" + }, + { + "filename": "about.html", + "title": "About", + "html": "
\n\n
\n

About OLS Digital

\n

Who we are and what we believe in.

\n
\n
\n

Our Story

OLS Digital was founded to bring structure, resources, and long-term support to promising digital brands. Rather than absorbing the businesses we work with, we help them keep their independent identity while benefiting from shared operational support.

Our Mission

We believe in honesty, quality, and putting people first. Every brand under the OLS Digital name is expected to uphold these same values in how they serve their customers.

\n
\n

Have Questions?

\n

We'd love to hear from you.

\n \n
\n
" + }, + { + "filename": "contact.html", + "title": "Contact", + "html": "
\n\n
\n

Contact Us

\n

Have a question about OLS Digital or one of our brands? We're happy to help.

\n
\n
\n

Get In Touch

For all inquiries regarding OLS Digital, AnHonestHost, StreamerTools, or any of our other brands, please reach out via email and our team will respond as soon as possible.

info@olsdigital.com
" + } + ], + "header_html": "\n", + "footer_html": "", + "craft_state": "{\"ai-hero-1\":{\"type\":{\"resolvedName\":\"HeroSimple\"},\"isCanvas\":false,\"props\":{\"heading\":\"OLS Digital\",\"subtitle\":\"The parent company behind a growing family of trusted online brands, including AnHonestHost and StreamerTools.\",\"ctas\":[{\"text\":\"Explore Our Brands\",\"href\":\"/brands\",\"variant\":\"primary\"},{\"text\":\"Contact Us\",\"href\":\"/contact\",\"variant\":\"outline\"}],\"bgType\":\"gradient\",\"bgColor\":\"#1e293b\",\"bgGradientFrom\":\"#0f172a\",\"bgGradientTo\":\"#334155\",\"bgGradientAngle\":135,\"bgImage\":\"\",\"bgPosition\":\"\",\"bgVideo\":\"\",\"overlayColor\":\"#000000\",\"overlayOpacity\":0,\"textColor\":\"#ffffff\",\"buttonBgColor\":\"#3b82f6\",\"buttonTextColor\":\"#ffffff\",\"minHeight\":\"60vh\",\"verticalAlign\":\"center\",\"textAlign\":\"center\",\"anchorId\":\"home\",\"style\":{},\"aiName\":\"Hero\",\"node_id\":\"ai-hero-1\"},\"displayName\":\"Hero\",\"custom\":{},\"parent\":\"ROOT\",\"hidden\":false,\"nodes\":[],\"linkedNodes\":{}},\"ai-features-1\":{\"type\":{\"resolvedName\":\"FeaturesGrid\"},\"isCanvas\":false,\"props\":{\"features\":[{\"icon\":\"\ud83c\udfe2\",\"title\":\"Multi-Brand Portfolio\",\"description\":\"We own and support a growing collection of independent, high-quality brands.\"},{\"icon\":\"\ud83c\udf10\",\"title\":\"AnHonestHost\",\"description\":\"Transparent, reliable web hosting built on trust.\"},{\"icon\":\"\ud83c\udfae\",\"title\":\"StreamerTools\",\"description\":\"Tools and resources built for content creators and streamers.\"}],\"style\":{\"backgroundColor\":\"#ffffff\"},\"anchorId\":\"what-we-do\",\"animation\":\"\",\"animationDelay\":\"\",\"hideOnDesktop\":false,\"hideOnTablet\":false,\"hideOnMobile\":false,\"aiName\":\"What We Do\",\"node_id\":\"ai-features-1\"},\"displayName\":\"Features Grid\",\"custom\":{},\"parent\":\"ROOT\",\"hidden\":false,\"nodes\":[],\"linkedNodes\":{}},\"ai-section-intro-1\":{\"type\":{\"resolvedName\":\"Section\"},\"isCanvas\":false,\"props\":{\"style\":{\"paddingTop\":\"60px\",\"paddingBottom\":\"60px\"},\"innerMaxWidth\":\"1200px\",\"topDivider\":\"none\",\"topDividerColor\":\"#ffffff\",\"topDividerHeight\":\"50px\",\"bottomDivider\":\"none\",\"bottomDividerColor\":\"#ffffff\",\"bottomDividerHeight\":\"50px\",\"anchorId\":\"about-preview\",\"animation\":\"\",\"animationDelay\":\"0\",\"hideOnDesktop\":false,\"hideOnTablet\":false,\"hideOnMobile\":false,\"aiName\":\"Intro Section\",\"node_id\":\"ai-section-intro-1\"},\"displayName\":\"Section\",\"custom\":{},\"parent\":\"ROOT\",\"hidden\":false,\"nodes\":[],\"linkedNodes\":{\"section-inner\":\"ai-section-intro-1__section-inner\"}},\"ai-heading-intro-1\":{\"type\":{\"resolvedName\":\"Heading\"},\"isCanvas\":false,\"props\":{\"text\":\"Building Brands That Matter\",\"html\":\"\",\"level\":\"h2\",\"style\":{\"fontSize\":\"36px\",\"fontWeight\":\"700\",\"fontFamily\":\"Inter, sans-serif\",\"color\":\"#1f2937\",\"marginBottom\":\"16px\",\"lineHeight\":\"\",\"letterSpacing\":\"\",\"textTransform\":\"\",\"fontStyle\":\"\",\"textDecoration\":\"\",\"marginTop\":\"\",\"marginRight\":\"\",\"marginLeft\":\"\",\"paddingTop\":\"\",\"paddingRight\":\"\",\"paddingBottom\":\"\",\"paddingLeft\":\"\",\"border\":\"none\",\"boxShadow\":\"none\",\"opacity\":\"1\"},\"animation\":\"\",\"animationDelay\":\"0\",\"hideOnDesktop\":false,\"hideOnTablet\":false,\"hideOnMobile\":false,\"aiName\":\"Intro Heading\",\"node_id\":\"ai-heading-intro-1\"},\"displayName\":\"Heading\",\"custom\":{},\"parent\":\"ai-section-intro-1__section-inner\",\"hidden\":false,\"nodes\":[],\"linkedNodes\":{}},\"ai-text-intro-1\":{\"type\":{\"resolvedName\":\"TextBlock\"},\"isCanvas\":false,\"props\":{\"text\":\"OLS Digital is a privately held parent company focused on acquiring and growing digital-first businesses. Each brand under our umbrella operates independently, guided by a shared commitment to honesty, quality, and great customer experiences.\",\"html\":\"\",\"style\":{\"fontSize\":\"16px\",\"lineHeight\":\"1.6\",\"color\":\"#3f3f46\",\"letterSpacing\":\"\",\"textTransform\":\"\",\"fontStyle\":\"\",\"textDecoration\":\"\",\"marginTop\":\"\",\"marginRight\":\"\",\"marginBottom\":\"\",\"marginLeft\":\"\",\"paddingTop\":\"\",\"paddingRight\":\"\",\"paddingBottom\":\"\",\"paddingLeft\":\"\",\"border\":\"none\",\"boxShadow\":\"none\",\"opacity\":\"1\"},\"animation\":\"\",\"animationDelay\":\"0\",\"hideOnDesktop\":false,\"hideOnTablet\":false,\"hideOnMobile\":false,\"aiName\":\"Intro Text\",\"node_id\":\"ai-text-intro-1\"},\"displayName\":\"Text\",\"custom\":{},\"parent\":\"ai-section-intro-1__section-inner\",\"hidden\":false,\"nodes\":[],\"linkedNodes\":{}},\"ai-section-intro-1__section-inner\":{\"type\":{\"resolvedName\":\"Container\"},\"isCanvas\":true,\"props\":{\"style\":{\"padding\":\"20px\",\"minHeight\":\"100px\",\"justifyContent\":\"\",\"marginTop\":\"\",\"marginRight\":\"\",\"marginBottom\":\"\",\"marginLeft\":\"\",\"paddingTop\":\"\",\"paddingRight\":\"\",\"paddingBottom\":\"\",\"paddingLeft\":\"\",\"border\":\"none\",\"boxShadow\":\"none\",\"opacity\":\"1\"},\"tag\":\"div\",\"fullWidth\":false,\"contentWidth\":\"full\",\"anchorId\":\"\",\"cssId\":\"\",\"cssClass\":\"\",\"animation\":\"\",\"animationDelay\":\"0\",\"hideOnDesktop\":false,\"hideOnTablet\":false,\"hideOnMobile\":false},\"displayName\":\"Container\",\"custom\":{},\"parent\":\"ai-section-intro-1\",\"hidden\":false,\"nodes\":[\"ai-heading-intro-1\",\"ai-text-intro-1\"],\"linkedNodes\":{}},\"ai-cta-1\":{\"type\":{\"resolvedName\":\"CTASection\"},\"isCanvas\":false,\"props\":{\"heading\":\"Want to Learn More?\",\"description\":\"For inquiries about OLS Digital or any of our brands, reach out to our team directly.\",\"ctas\":[{\"text\":\"Email info@olsdigital.com\",\"href\":\"mailto:info@olsdigital.com\",\"variant\":\"primary\"}],\"gradient\":\"linear-gradient(135deg, #2563eb 0%, #7c3aed 100%)\",\"anchorId\":\"contact-cta\",\"style\":{},\"animation\":\"\",\"animationDelay\":\"\",\"hideOnDesktop\":false,\"hideOnTablet\":false,\"hideOnMobile\":false,\"aiName\":\"Contact CTA\",\"node_id\":\"ai-cta-1\"},\"displayName\":\"CTA Section\",\"custom\":{},\"parent\":\"ROOT\",\"hidden\":false,\"nodes\":[],\"linkedNodes\":{}},\"ROOT\":{\"type\":{\"resolvedName\":\"Container\"},\"isCanvas\":true,\"props\":{\"style\":{\"padding\":\"20px\",\"minHeight\":\"100px\",\"justifyContent\":\"\",\"marginTop\":\"\",\"marginRight\":\"\",\"marginBottom\":\"\",\"marginLeft\":\"\",\"paddingTop\":\"\",\"paddingRight\":\"\",\"paddingBottom\":\"\",\"paddingLeft\":\"\",\"border\":\"none\",\"boxShadow\":\"none\",\"opacity\":\"1\"},\"tag\":\"div\",\"fullWidth\":false,\"contentWidth\":\"full\",\"anchorId\":\"\",\"cssId\":\"\",\"cssClass\":\"\",\"animation\":\"\",\"animationDelay\":\"0\",\"hideOnDesktop\":false,\"hideOnTablet\":false,\"hideOnMobile\":false,\"aiName\":\"Root\",\"node_id\":\"ai-root-home\"},\"displayName\":\"Container\",\"custom\":{},\"parent\":null,\"hidden\":false,\"nodes\":[\"ai-hero-1\",\"ai-features-1\",\"ai-section-intro-1\",\"ai-cta-1\"],\"linkedNodes\":{}}}", + "header_craft_state": "{\"ROOT\":{\"type\":{\"resolvedName\":\"Navbar\"},\"isCanvas\":true,\"props\":{\"logoType\":\"image\",\"logoText\":\"\",\"logoImage\":\"/api/assets-proxy/?site_id=100&filename=1789158005_2592c5cf_Minimalist_OLS_Digital_Logo_with_Rounded_Elements__400_x_135_px_.webp\",\"logoWidth\":\"120px\",\"logoUrl\":\"/\",\"logoFontFamily\":\"Inter, sans-serif\",\"logoFontSize\":\"20px\",\"links\":[{\"text\":\"Home\",\"href\":\"/\",\"source\":\"page\",\"pageId\":\"home\"},{\"text\":\"Our Brands\",\"href\":\"/brands\",\"source\":\"page\",\"pageId\":\"page_mtxec41h_1\"},{\"text\":\"About\",\"href\":\"/about\",\"source\":\"page\",\"pageId\":\"page_mtxec41h_2\"},{\"text\":\"Contact\",\"href\":\"/contact\",\"source\":\"page\",\"pageId\":\"page_mtxec41h_3\"},{\"text\":\"Contact\",\"href\":\"/contact\",\"isCta\":true}],\"followPages\":true,\"backgroundColor\":\"#0f172a\",\"textColor\":\"#ffffff\",\"hoverColor\":\"#3b82f6\",\"ctaColor\":\"#3b82f6\",\"ctaTextColor\":\"#ffffff\",\"padding\":\"16px 24px\",\"navAlignment\":\"space-between\",\"isSticky\":false,\"showMobileMenu\":false,\"style\":{\"borderBottom\":\"1px solid #e4e4e7\"},\"hideOnDesktop\":false,\"hideOnTablet\":false,\"hideOnMobile\":false,\"animation\":\"none\",\"animationDelay\":\"0\",\"aiName\":\"Site Nav\",\"node_id\":\"ai-nav-1\"},\"displayName\":\"Navbar\",\"custom\":{},\"parent\":null,\"hidden\":false,\"nodes\":[],\"linkedNodes\":{}}}", + "footer_craft_state": "{\"ROOT\":{\"type\":{\"resolvedName\":\"Footer\"},\"isCanvas\":true,\"props\":{\"aiName\":\"Site Footer\",\"node_id\":\"ai-footer-1\",\"text\":\"\u00a9 2026 OLS Digital. All rights reserved. Questions? Email info@olsdigital.com\"},\"displayName\":\"Footer\",\"custom\":{},\"hidden\":false,\"parent\":null,\"nodes\":[],\"linkedNodes\":{}}}", + "pages_craft_state": [ + { + "id": "home", + "name": "Home", + "slug": "index", + "craftState": "{\"ai-hero-1\":{\"type\":{\"resolvedName\":\"HeroSimple\"},\"isCanvas\":false,\"props\":{\"heading\":\"OLS Digital\",\"subtitle\":\"The parent company behind a growing family of trusted online brands, including AnHonestHost and StreamerTools.\",\"ctas\":[{\"text\":\"Explore Our Brands\",\"href\":\"/brands\",\"variant\":\"primary\"},{\"text\":\"Contact Us\",\"href\":\"/contact\",\"variant\":\"outline\"}],\"bgType\":\"gradient\",\"bgColor\":\"#1e293b\",\"bgGradientFrom\":\"#0f172a\",\"bgGradientTo\":\"#334155\",\"bgGradientAngle\":135,\"bgImage\":\"\",\"bgPosition\":\"\",\"bgVideo\":\"\",\"overlayColor\":\"#000000\",\"overlayOpacity\":0,\"textColor\":\"#ffffff\",\"buttonBgColor\":\"#3b82f6\",\"buttonTextColor\":\"#ffffff\",\"minHeight\":\"60vh\",\"verticalAlign\":\"center\",\"textAlign\":\"center\",\"anchorId\":\"home\",\"style\":{},\"aiName\":\"Hero\",\"node_id\":\"ai-hero-1\"},\"displayName\":\"Hero\",\"custom\":{},\"parent\":\"ROOT\",\"hidden\":false,\"nodes\":[],\"linkedNodes\":{}},\"ai-features-1\":{\"type\":{\"resolvedName\":\"FeaturesGrid\"},\"isCanvas\":false,\"props\":{\"features\":[{\"icon\":\"\ud83c\udfe2\",\"title\":\"Multi-Brand Portfolio\",\"description\":\"We own and support a growing collection of independent, high-quality brands.\"},{\"icon\":\"\ud83c\udf10\",\"title\":\"AnHonestHost\",\"description\":\"Transparent, reliable web hosting built on trust.\"},{\"icon\":\"\ud83c\udfae\",\"title\":\"StreamerTools\",\"description\":\"Tools and resources built for content creators and streamers.\"}],\"style\":{\"backgroundColor\":\"#ffffff\"},\"anchorId\":\"what-we-do\",\"animation\":\"\",\"animationDelay\":\"\",\"hideOnDesktop\":false,\"hideOnTablet\":false,\"hideOnMobile\":false,\"aiName\":\"What We Do\",\"node_id\":\"ai-features-1\"},\"displayName\":\"Features Grid\",\"custom\":{},\"parent\":\"ROOT\",\"hidden\":false,\"nodes\":[],\"linkedNodes\":{}},\"ai-section-intro-1\":{\"type\":{\"resolvedName\":\"Section\"},\"isCanvas\":false,\"props\":{\"style\":{\"paddingTop\":\"60px\",\"paddingBottom\":\"60px\"},\"innerMaxWidth\":\"1200px\",\"topDivider\":\"none\",\"topDividerColor\":\"#ffffff\",\"topDividerHeight\":\"50px\",\"bottomDivider\":\"none\",\"bottomDividerColor\":\"#ffffff\",\"bottomDividerHeight\":\"50px\",\"anchorId\":\"about-preview\",\"animation\":\"\",\"animationDelay\":\"0\",\"hideOnDesktop\":false,\"hideOnTablet\":false,\"hideOnMobile\":false,\"aiName\":\"Intro Section\",\"node_id\":\"ai-section-intro-1\"},\"displayName\":\"Section\",\"custom\":{},\"parent\":\"ROOT\",\"hidden\":false,\"nodes\":[],\"linkedNodes\":{\"section-inner\":\"ai-section-intro-1__section-inner\"}},\"ai-heading-intro-1\":{\"type\":{\"resolvedName\":\"Heading\"},\"isCanvas\":false,\"props\":{\"text\":\"Building Brands That Matter\",\"html\":\"\",\"level\":\"h2\",\"style\":{\"fontSize\":\"36px\",\"fontWeight\":\"700\",\"fontFamily\":\"Inter, sans-serif\",\"color\":\"#1f2937\",\"marginBottom\":\"16px\",\"lineHeight\":\"\",\"letterSpacing\":\"\",\"textTransform\":\"\",\"fontStyle\":\"\",\"textDecoration\":\"\",\"marginTop\":\"\",\"marginRight\":\"\",\"marginLeft\":\"\",\"paddingTop\":\"\",\"paddingRight\":\"\",\"paddingBottom\":\"\",\"paddingLeft\":\"\",\"border\":\"none\",\"boxShadow\":\"none\",\"opacity\":\"1\"},\"animation\":\"\",\"animationDelay\":\"0\",\"hideOnDesktop\":false,\"hideOnTablet\":false,\"hideOnMobile\":false,\"aiName\":\"Intro Heading\",\"node_id\":\"ai-heading-intro-1\"},\"displayName\":\"Heading\",\"custom\":{},\"parent\":\"ai-section-intro-1__section-inner\",\"hidden\":false,\"nodes\":[],\"linkedNodes\":{}},\"ai-text-intro-1\":{\"type\":{\"resolvedName\":\"TextBlock\"},\"isCanvas\":false,\"props\":{\"text\":\"OLS Digital is a privately held parent company focused on acquiring and growing digital-first businesses. Each brand under our umbrella operates independently, guided by a shared commitment to honesty, quality, and great customer experiences.\",\"html\":\"\",\"style\":{\"fontSize\":\"16px\",\"lineHeight\":\"1.6\",\"color\":\"#3f3f46\",\"letterSpacing\":\"\",\"textTransform\":\"\",\"fontStyle\":\"\",\"textDecoration\":\"\",\"marginTop\":\"\",\"marginRight\":\"\",\"marginBottom\":\"\",\"marginLeft\":\"\",\"paddingTop\":\"\",\"paddingRight\":\"\",\"paddingBottom\":\"\",\"paddingLeft\":\"\",\"border\":\"none\",\"boxShadow\":\"none\",\"opacity\":\"1\"},\"animation\":\"\",\"animationDelay\":\"0\",\"hideOnDesktop\":false,\"hideOnTablet\":false,\"hideOnMobile\":false,\"aiName\":\"Intro Text\",\"node_id\":\"ai-text-intro-1\"},\"displayName\":\"Text\",\"custom\":{},\"parent\":\"ai-section-intro-1__section-inner\",\"hidden\":false,\"nodes\":[],\"linkedNodes\":{}},\"ai-section-intro-1__section-inner\":{\"type\":{\"resolvedName\":\"Container\"},\"isCanvas\":true,\"props\":{\"style\":{\"padding\":\"20px\",\"minHeight\":\"100px\",\"justifyContent\":\"\",\"marginTop\":\"\",\"marginRight\":\"\",\"marginBottom\":\"\",\"marginLeft\":\"\",\"paddingTop\":\"\",\"paddingRight\":\"\",\"paddingBottom\":\"\",\"paddingLeft\":\"\",\"border\":\"none\",\"boxShadow\":\"none\",\"opacity\":\"1\"},\"tag\":\"div\",\"fullWidth\":false,\"contentWidth\":\"full\",\"anchorId\":\"\",\"cssId\":\"\",\"cssClass\":\"\",\"animation\":\"\",\"animationDelay\":\"0\",\"hideOnDesktop\":false,\"hideOnTablet\":false,\"hideOnMobile\":false},\"displayName\":\"Container\",\"custom\":{},\"parent\":\"ai-section-intro-1\",\"hidden\":false,\"nodes\":[\"ai-heading-intro-1\",\"ai-text-intro-1\"],\"linkedNodes\":{}},\"ai-cta-1\":{\"type\":{\"resolvedName\":\"CTASection\"},\"isCanvas\":false,\"props\":{\"heading\":\"Want to Learn More?\",\"description\":\"For inquiries about OLS Digital or any of our brands, reach out to our team directly.\",\"ctas\":[{\"text\":\"Email info@olsdigital.com\",\"href\":\"mailto:info@olsdigital.com\",\"variant\":\"primary\"}],\"gradient\":\"linear-gradient(135deg, #2563eb 0%, #7c3aed 100%)\",\"anchorId\":\"contact-cta\",\"style\":{},\"animation\":\"\",\"animationDelay\":\"\",\"hideOnDesktop\":false,\"hideOnTablet\":false,\"hideOnMobile\":false,\"aiName\":\"Contact CTA\",\"node_id\":\"ai-cta-1\"},\"displayName\":\"CTA Section\",\"custom\":{},\"parent\":\"ROOT\",\"hidden\":false,\"nodes\":[],\"linkedNodes\":{}},\"ROOT\":{\"type\":{\"resolvedName\":\"Container\"},\"isCanvas\":true,\"props\":{\"style\":{\"padding\":\"20px\",\"minHeight\":\"100px\",\"justifyContent\":\"\",\"marginTop\":\"\",\"marginRight\":\"\",\"marginBottom\":\"\",\"marginLeft\":\"\",\"paddingTop\":\"\",\"paddingRight\":\"\",\"paddingBottom\":\"\",\"paddingLeft\":\"\",\"border\":\"none\",\"boxShadow\":\"none\",\"opacity\":\"1\"},\"tag\":\"div\",\"fullWidth\":false,\"contentWidth\":\"full\",\"anchorId\":\"\",\"cssId\":\"\",\"cssClass\":\"\",\"animation\":\"\",\"animationDelay\":\"0\",\"hideOnDesktop\":false,\"hideOnTablet\":false,\"hideOnMobile\":false,\"aiName\":\"Root\",\"node_id\":\"ai-root-home\"},\"displayName\":\"Container\",\"custom\":{},\"parent\":null,\"hidden\":false,\"nodes\":[\"ai-hero-1\",\"ai-features-1\",\"ai-section-intro-1\",\"ai-cta-1\"],\"linkedNodes\":{}}}" + }, + { + "id": "page_mtxec41h_1", + "name": "Brands", + "slug": "brands", + "craftState": "{\"ai-hero-brands-1\":{\"type\":{\"resolvedName\":\"HeroSimple\"},\"isCanvas\":false,\"props\":{\"heading\":\"Our Brands\",\"subtitle\":\"A closer look at the companies under the OLS Digital umbrella.\",\"ctas\":[],\"bgType\":\"color\",\"bgColor\":\"#1e293b\",\"bgGradientFrom\":\"#667eea\",\"bgGradientTo\":\"#764ba2\",\"bgGradientAngle\":135,\"bgImage\":\"\",\"bgPosition\":\"\",\"bgVideo\":\"\",\"overlayColor\":\"#000000\",\"overlayOpacity\":0,\"textColor\":\"#ffffff\",\"buttonBgColor\":\"#3b82f6\",\"buttonTextColor\":\"#ffffff\",\"minHeight\":\"35vh\",\"verticalAlign\":\"center\",\"textAlign\":\"center\",\"anchorId\":\"brands\",\"style\":{},\"aiName\":\"Brands Hero\",\"node_id\":\"ai-hero-brands-1\"},\"displayName\":\"Hero\",\"custom\":{},\"parent\":\"ROOT\",\"hidden\":false,\"nodes\":[],\"linkedNodes\":{}},\"ai-columns-anhonesthost-1\":{\"type\":{\"resolvedName\":\"ColumnLayout\"},\"isCanvas\":false,\"props\":{\"columns\":2,\"split\":\"40-60\",\"gap\":\"40px\",\"style\":{\"paddingTop\":\"60px\",\"paddingBottom\":\"20px\"},\"anchorId\":\"anhonesthost\",\"animation\":\"\",\"animationDelay\":\"0\",\"hideOnDesktop\":false,\"hideOnTablet\":false,\"hideOnMobile\":false,\"aiName\":\"Brand: AnHonestHost\",\"node_id\":\"ai-columns-anhonesthost-1\"},\"displayName\":\"Columns\",\"custom\":{},\"parent\":\"ROOT\",\"hidden\":false,\"nodes\":[],\"linkedNodes\":{\"col-0\":\"K8SJDt59Ct\",\"col-1\":\"ai-container-anhonesthost-1\"}},\"ai-container-anhonesthost-1\":{\"type\":{\"resolvedName\":\"Container\"},\"isCanvas\":true,\"props\":{\"style\":{\"padding\":\"20px\",\"minHeight\":\"100px\",\"justifyContent\":\"\",\"marginTop\":\"\",\"marginRight\":\"\",\"marginBottom\":\"\",\"marginLeft\":\"\",\"paddingTop\":\"\",\"paddingRight\":\"\",\"paddingBottom\":\"\",\"paddingLeft\":\"\",\"border\":\"none\",\"boxShadow\":\"none\",\"opacity\":\"1\"},\"tag\":\"div\",\"fullWidth\":false,\"contentWidth\":\"full\",\"anchorId\":\"\",\"cssId\":\"\",\"cssClass\":\"\",\"animation\":\"\",\"animationDelay\":\"0\",\"hideOnDesktop\":false,\"hideOnTablet\":false,\"hideOnMobile\":false,\"aiName\":\"AnHonestHost Text\",\"node_id\":\"ai-container-anhonesthost-1\"},\"displayName\":\"Container\",\"custom\":{},\"parent\":\"ai-columns-anhonesthost-1\",\"hidden\":false,\"nodes\":[\"ai-heading-anhonesthost-1\",\"ai-text-anhonesthost-1\"],\"linkedNodes\":{}},\"ai-heading-anhonesthost-1\":{\"type\":{\"resolvedName\":\"Heading\"},\"isCanvas\":false,\"props\":{\"text\":\"AnHonestHost\",\"html\":\"\",\"level\":\"h2\",\"style\":{\"fontSize\":\"36px\",\"fontWeight\":\"700\",\"fontFamily\":\"Inter, sans-serif\",\"color\":\"#1f2937\",\"marginBottom\":\"16px\",\"lineHeight\":\"\",\"letterSpacing\":\"\",\"textTransform\":\"\",\"fontStyle\":\"\",\"textDecoration\":\"\",\"marginTop\":\"\",\"marginRight\":\"\",\"marginLeft\":\"\",\"paddingTop\":\"\",\"paddingRight\":\"\",\"paddingBottom\":\"\",\"paddingLeft\":\"\",\"border\":\"none\",\"boxShadow\":\"none\",\"opacity\":\"1\"},\"animation\":\"\",\"animationDelay\":\"0\",\"hideOnDesktop\":false,\"hideOnTablet\":false,\"hideOnMobile\":false,\"aiName\":\"AnHonestHost Heading\",\"node_id\":\"ai-heading-anhonesthost-1\"},\"displayName\":\"Heading\",\"custom\":{},\"parent\":\"ai-container-anhonesthost-1\",\"hidden\":false,\"nodes\":[],\"linkedNodes\":{}},\"ai-text-anhonesthost-1\":{\"type\":{\"resolvedName\":\"TextBlock\"},\"isCanvas\":false,\"props\":{\"text\":\"AnHonestHost provides transparent, no-nonsense web hosting for individuals and businesses. Straightforward pricing, honest support, and reliable infrastructure \u2014 no surprises.\",\"html\":\"\",\"style\":{\"fontSize\":\"16px\",\"lineHeight\":\"1.6\",\"color\":\"#3f3f46\",\"letterSpacing\":\"\",\"textTransform\":\"\",\"fontStyle\":\"\",\"textDecoration\":\"\",\"marginTop\":\"\",\"marginRight\":\"\",\"marginBottom\":\"\",\"marginLeft\":\"\",\"paddingTop\":\"\",\"paddingRight\":\"\",\"paddingBottom\":\"\",\"paddingLeft\":\"\",\"border\":\"none\",\"boxShadow\":\"none\",\"opacity\":\"1\"},\"animation\":\"\",\"animationDelay\":\"0\",\"hideOnDesktop\":false,\"hideOnTablet\":false,\"hideOnMobile\":false,\"aiName\":\"AnHonestHost Description\",\"node_id\":\"ai-text-anhonesthost-1\"},\"displayName\":\"Text\",\"custom\":{},\"parent\":\"ai-container-anhonesthost-1\",\"hidden\":false,\"nodes\":[],\"linkedNodes\":{}},\"ai-divider-1\":{\"type\":{\"resolvedName\":\"Divider\"},\"isCanvas\":false,\"props\":{\"color\":\"#e2e8f0\",\"thickness\":\"1px\",\"style\":{},\"aiName\":\"Divider 1\",\"node_id\":\"ai-divider-1\"},\"displayName\":\"Divider\",\"custom\":{},\"parent\":\"ROOT\",\"hidden\":false,\"nodes\":[],\"linkedNodes\":{}},\"ai-columns-streamertools-1\":{\"type\":{\"resolvedName\":\"ColumnLayout\"},\"isCanvas\":false,\"props\":{\"columns\":2,\"split\":\"60-40\",\"gap\":\"40px\",\"style\":{\"paddingTop\":\"60px\",\"paddingBottom\":\"60px\"},\"anchorId\":\"streamertools\",\"animation\":\"\",\"animationDelay\":\"0\",\"hideOnDesktop\":false,\"hideOnTablet\":false,\"hideOnMobile\":false,\"aiName\":\"Brand: StreamerTools\",\"node_id\":\"ai-columns-streamertools-1\"},\"displayName\":\"Columns\",\"custom\":{},\"parent\":\"ROOT\",\"hidden\":false,\"nodes\":[],\"linkedNodes\":{\"col-0\":\"ai-container-streamertools-1\",\"col-1\":\"BoOVT1AGGy\"}},\"ai-container-streamertools-1\":{\"type\":{\"resolvedName\":\"Container\"},\"isCanvas\":true,\"props\":{\"style\":{\"padding\":\"20px\",\"minHeight\":\"100px\",\"justifyContent\":\"\",\"marginTop\":\"\",\"marginRight\":\"\",\"marginBottom\":\"\",\"marginLeft\":\"\",\"paddingTop\":\"\",\"paddingRight\":\"\",\"paddingBottom\":\"\",\"paddingLeft\":\"\",\"border\":\"none\",\"boxShadow\":\"none\",\"opacity\":\"1\"},\"tag\":\"div\",\"fullWidth\":false,\"contentWidth\":\"full\",\"anchorId\":\"\",\"cssId\":\"\",\"cssClass\":\"\",\"animation\":\"\",\"animationDelay\":\"0\",\"hideOnDesktop\":false,\"hideOnTablet\":false,\"hideOnMobile\":false,\"aiName\":\"StreamerTools Text\",\"node_id\":\"ai-container-streamertools-1\"},\"displayName\":\"Container\",\"custom\":{},\"parent\":\"ai-columns-streamertools-1\",\"hidden\":false,\"nodes\":[\"ai-heading-streamertools-1\",\"ai-text-streamertools-1\"],\"linkedNodes\":{}},\"ai-heading-streamertools-1\":{\"type\":{\"resolvedName\":\"Heading\"},\"isCanvas\":false,\"props\":{\"text\":\"StreamerTools\",\"html\":\"\",\"level\":\"h2\",\"style\":{\"fontSize\":\"36px\",\"fontWeight\":\"700\",\"fontFamily\":\"Inter, sans-serif\",\"color\":\"#1f2937\",\"marginBottom\":\"16px\",\"lineHeight\":\"\",\"letterSpacing\":\"\",\"textTransform\":\"\",\"fontStyle\":\"\",\"textDecoration\":\"\",\"marginTop\":\"\",\"marginRight\":\"\",\"marginLeft\":\"\",\"paddingTop\":\"\",\"paddingRight\":\"\",\"paddingBottom\":\"\",\"paddingLeft\":\"\",\"border\":\"none\",\"boxShadow\":\"none\",\"opacity\":\"1\"},\"animation\":\"\",\"animationDelay\":\"0\",\"hideOnDesktop\":false,\"hideOnTablet\":false,\"hideOnMobile\":false,\"aiName\":\"StreamerTools Heading\",\"node_id\":\"ai-heading-streamertools-1\"},\"displayName\":\"Heading\",\"custom\":{},\"parent\":\"ai-container-streamertools-1\",\"hidden\":false,\"nodes\":[],\"linkedNodes\":{}},\"ai-text-streamertools-1\":{\"type\":{\"resolvedName\":\"TextBlock\"},\"isCanvas\":false,\"props\":{\"text\":\"StreamerTools builds practical tools and resources for streamers and content creators, helping them grow their channels and streamline their workflow.\",\"html\":\"\",\"style\":{\"fontSize\":\"16px\",\"lineHeight\":\"1.6\",\"color\":\"#3f3f46\",\"letterSpacing\":\"\",\"textTransform\":\"\",\"fontStyle\":\"\",\"textDecoration\":\"\",\"marginTop\":\"\",\"marginRight\":\"\",\"marginBottom\":\"\",\"marginLeft\":\"\",\"paddingTop\":\"\",\"paddingRight\":\"\",\"paddingBottom\":\"\",\"paddingLeft\":\"\",\"border\":\"none\",\"boxShadow\":\"none\",\"opacity\":\"1\"},\"animation\":\"\",\"animationDelay\":\"0\",\"hideOnDesktop\":false,\"hideOnTablet\":false,\"hideOnMobile\":false,\"aiName\":\"StreamerTools Description\",\"node_id\":\"ai-text-streamertools-1\"},\"displayName\":\"Text\",\"custom\":{},\"parent\":\"ai-container-streamertools-1\",\"hidden\":false,\"nodes\":[],\"linkedNodes\":{}},\"ai-cta-brands-1\":{\"type\":{\"resolvedName\":\"CTASection\"},\"isCanvas\":false,\"props\":{\"heading\":\"Interested in One of Our Brands?\",\"description\":\"Reach out and we'll point you in the right direction.\",\"ctas\":[{\"text\":\"Email info@olsdigital.com\",\"href\":\"mailto:info@olsdigital.com\",\"variant\":\"primary\"}],\"gradient\":\"linear-gradient(135deg, #2563eb 0%, #7c3aed 100%)\",\"anchorId\":\"brands-contact\",\"style\":{},\"animation\":\"\",\"animationDelay\":\"\",\"hideOnDesktop\":false,\"hideOnTablet\":false,\"hideOnMobile\":false,\"aiName\":\"Brands CTA\",\"node_id\":\"ai-cta-brands-1\"},\"displayName\":\"CTA Section\",\"custom\":{},\"parent\":\"ROOT\",\"hidden\":false,\"nodes\":[],\"linkedNodes\":{}},\"ROOT\":{\"type\":{\"resolvedName\":\"Container\"},\"isCanvas\":true,\"props\":{\"style\":{\"padding\":\"20px\",\"minHeight\":\"100px\",\"justifyContent\":\"\",\"marginTop\":\"\",\"marginRight\":\"\",\"marginBottom\":\"\",\"marginLeft\":\"\",\"paddingTop\":\"\",\"paddingRight\":\"\",\"paddingBottom\":\"\",\"paddingLeft\":\"\",\"border\":\"none\",\"boxShadow\":\"none\",\"opacity\":\"1\"},\"tag\":\"div\",\"fullWidth\":false,\"contentWidth\":\"full\",\"anchorId\":\"\",\"cssId\":\"\",\"cssClass\":\"\",\"animation\":\"\",\"animationDelay\":\"0\",\"hideOnDesktop\":false,\"hideOnTablet\":false,\"hideOnMobile\":false,\"aiName\":\"Root\",\"node_id\":\"ai-root-brands\"},\"displayName\":\"Container\",\"custom\":{},\"parent\":null,\"hidden\":false,\"nodes\":[\"ai-hero-brands-1\",\"ai-columns-anhonesthost-1\",\"ai-divider-1\",\"ai-columns-streamertools-1\",\"ai-cta-brands-1\"],\"linkedNodes\":{}},\"K8SJDt59Ct\":{\"type\":{\"resolvedName\":\"Container\"},\"isCanvas\":true,\"props\":{\"style\":{\"flex\":\"0 0 calc(40% - 40px)\",\"minHeight\":\"60px\",\"padding\":\"8px\"},\"tag\":\"div\",\"fullWidth\":false,\"contentWidth\":\"full\",\"anchorId\":\"\",\"cssId\":\"\",\"cssClass\":\"\",\"animation\":\"\",\"animationDelay\":\"0\",\"hideOnDesktop\":false,\"hideOnTablet\":false,\"hideOnMobile\":false},\"displayName\":\"Container\",\"custom\":{\"className\":\"craft-column\"},\"parent\":\"ai-columns-anhonesthost-1\",\"hidden\":false,\"nodes\":[],\"linkedNodes\":{}},\"BoOVT1AGGy\":{\"type\":{\"resolvedName\":\"Container\"},\"isCanvas\":true,\"props\":{\"style\":{\"flex\":\"0 0 calc(40% - 40px)\",\"minHeight\":\"60px\",\"padding\":\"8px\"},\"tag\":\"div\",\"fullWidth\":false,\"contentWidth\":\"full\",\"anchorId\":\"\",\"cssId\":\"\",\"cssClass\":\"\",\"animation\":\"\",\"animationDelay\":\"0\",\"hideOnDesktop\":false,\"hideOnTablet\":false,\"hideOnMobile\":false},\"displayName\":\"Container\",\"custom\":{\"className\":\"craft-column\"},\"parent\":\"ai-columns-streamertools-1\",\"hidden\":false,\"nodes\":[],\"linkedNodes\":{}}}", + "nav": { + "label": "Our Brands" + } + }, + { + "id": "page_mtxec41h_2", + "name": "About", + "slug": "about", + "craftState": "{\"ai-hero-about-1\":{\"type\":{\"resolvedName\":\"HeroSimple\"},\"isCanvas\":false,\"props\":{\"heading\":\"About OLS Digital\",\"subtitle\":\"Who we are and what we believe in.\",\"ctas\":[],\"bgType\":\"color\",\"bgColor\":\"#1e293b\",\"bgGradientFrom\":\"#667eea\",\"bgGradientTo\":\"#764ba2\",\"bgGradientAngle\":135,\"bgImage\":\"\",\"bgVideo\":\"\",\"overlayColor\":\"#000000\",\"overlayOpacity\":0,\"textColor\":\"#ffffff\",\"buttonBgColor\":\"#3b82f6\",\"buttonTextColor\":\"#ffffff\",\"minHeight\":\"35vh\",\"verticalAlign\":\"center\",\"textAlign\":\"center\",\"anchorId\":\"about\",\"style\":{},\"aiName\":\"About Hero\",\"node_id\":\"ai-hero-about-1\"},\"displayName\":\"Hero\",\"custom\":{},\"parent\":\"ROOT\",\"hidden\":false,\"nodes\":[],\"linkedNodes\":{}},\"ai-section-about-1\":{\"type\":{\"resolvedName\":\"Section\"},\"isCanvas\":false,\"props\":{\"style\":{\"paddingTop\":\"60px\",\"paddingBottom\":\"20px\"},\"innerMaxWidth\":\"1200px\",\"topDivider\":\"none\",\"topDividerColor\":\"#ffffff\",\"topDividerHeight\":\"50px\",\"bottomDivider\":\"none\",\"bottomDividerColor\":\"#ffffff\",\"bottomDividerHeight\":\"50px\",\"anchorId\":\"our-story\",\"animation\":\"\",\"animationDelay\":\"0\",\"hideOnDesktop\":false,\"hideOnTablet\":false,\"hideOnMobile\":false,\"aiName\":\"About Content\",\"node_id\":\"ai-section-about-1\"},\"displayName\":\"Section\",\"custom\":{},\"parent\":\"ROOT\",\"hidden\":false,\"nodes\":[],\"linkedNodes\":{\"section-inner\":\"ai-section-about-1__section-inner\"}},\"ai-heading-about-1\":{\"type\":{\"resolvedName\":\"Heading\"},\"isCanvas\":false,\"props\":{\"text\":\"Our Story\",\"level\":\"h2\",\"style\":{\"fontSize\":\"36px\",\"fontWeight\":\"700\",\"fontFamily\":\"Inter, sans-serif\",\"color\":\"#1f2937\",\"marginBottom\":\"16px\",\"lineHeight\":\"\",\"letterSpacing\":\"\",\"textTransform\":\"\",\"fontStyle\":\"\",\"textDecoration\":\"\",\"marginTop\":\"\",\"marginRight\":\"\",\"marginLeft\":\"\",\"paddingTop\":\"\",\"paddingRight\":\"\",\"paddingBottom\":\"\",\"paddingLeft\":\"\",\"border\":\"none\",\"boxShadow\":\"none\",\"opacity\":\"1\"},\"animation\":\"\",\"animationDelay\":\"0\",\"hideOnDesktop\":false,\"hideOnTablet\":false,\"hideOnMobile\":false,\"aiName\":\"Our Story Heading\",\"node_id\":\"ai-heading-about-1\"},\"displayName\":\"Heading\",\"custom\":{},\"parent\":\"ai-section-about-1__section-inner\",\"hidden\":false,\"nodes\":[],\"linkedNodes\":{}},\"ai-text-about-1\":{\"type\":{\"resolvedName\":\"TextBlock\"},\"isCanvas\":false,\"props\":{\"text\":\"OLS Digital was founded to bring structure, resources, and long-term support to promising digital brands. Rather than absorbing the businesses we work with, we help them keep their independent identity while benefiting from shared operational support.\",\"style\":{\"fontSize\":\"16px\",\"lineHeight\":\"1.6\",\"color\":\"#3f3f46\",\"letterSpacing\":\"\",\"textTransform\":\"\",\"fontStyle\":\"\",\"textDecoration\":\"\",\"marginTop\":\"\",\"marginRight\":\"\",\"marginBottom\":\"\",\"marginLeft\":\"\",\"paddingTop\":\"\",\"paddingRight\":\"\",\"paddingBottom\":\"\",\"paddingLeft\":\"\",\"border\":\"none\",\"boxShadow\":\"none\",\"opacity\":\"1\"},\"animation\":\"\",\"animationDelay\":\"0\",\"hideOnDesktop\":false,\"hideOnTablet\":false,\"hideOnMobile\":false,\"aiName\":\"Our Story Text\",\"node_id\":\"ai-text-about-1\"},\"displayName\":\"Text\",\"custom\":{},\"parent\":\"ai-section-about-1__section-inner\",\"hidden\":false,\"nodes\":[],\"linkedNodes\":{}},\"ai-section-about-1__section-inner\":{\"type\":{\"resolvedName\":\"Container\"},\"isCanvas\":true,\"props\":{\"style\":{\"padding\":\"20px\",\"minHeight\":\"100px\",\"justifyContent\":\"\",\"marginTop\":\"\",\"marginRight\":\"\",\"marginBottom\":\"\",\"marginLeft\":\"\",\"paddingTop\":\"\",\"paddingRight\":\"\",\"paddingBottom\":\"\",\"paddingLeft\":\"\",\"border\":\"none\",\"boxShadow\":\"none\",\"opacity\":\"1\"},\"tag\":\"div\",\"fullWidth\":false,\"contentWidth\":\"full\",\"anchorId\":\"\",\"cssId\":\"\",\"cssClass\":\"\",\"animation\":\"\",\"animationDelay\":\"0\",\"hideOnDesktop\":false,\"hideOnTablet\":false,\"hideOnMobile\":false},\"displayName\":\"Container\",\"custom\":{},\"parent\":\"ai-section-about-1\",\"hidden\":false,\"nodes\":[\"ai-heading-about-1\",\"ai-text-about-1\"],\"linkedNodes\":{}},\"ai-section-mission-1\":{\"type\":{\"resolvedName\":\"Section\"},\"isCanvas\":false,\"props\":{\"style\":{\"paddingTop\":\"20px\",\"paddingBottom\":\"60px\"},\"innerMaxWidth\":\"1200px\",\"topDivider\":\"none\",\"topDividerColor\":\"#ffffff\",\"topDividerHeight\":\"50px\",\"bottomDivider\":\"none\",\"bottomDividerColor\":\"#ffffff\",\"bottomDividerHeight\":\"50px\",\"anchorId\":\"our-mission\",\"animation\":\"\",\"animationDelay\":\"0\",\"hideOnDesktop\":false,\"hideOnTablet\":false,\"hideOnMobile\":false,\"aiName\":\"Our Mission\",\"node_id\":\"ai-section-mission-1\"},\"displayName\":\"Section\",\"custom\":{},\"parent\":\"ROOT\",\"hidden\":false,\"nodes\":[],\"linkedNodes\":{\"section-inner\":\"ai-section-mission-1__section-inner\"}},\"ai-heading-mission-1\":{\"type\":{\"resolvedName\":\"Heading\"},\"isCanvas\":false,\"props\":{\"text\":\"Our Mission\",\"level\":\"h2\",\"style\":{\"fontSize\":\"36px\",\"fontWeight\":\"700\",\"fontFamily\":\"Inter, sans-serif\",\"color\":\"#1f2937\",\"marginBottom\":\"16px\",\"lineHeight\":\"\",\"letterSpacing\":\"\",\"textTransform\":\"\",\"fontStyle\":\"\",\"textDecoration\":\"\",\"marginTop\":\"\",\"marginRight\":\"\",\"marginLeft\":\"\",\"paddingTop\":\"\",\"paddingRight\":\"\",\"paddingBottom\":\"\",\"paddingLeft\":\"\",\"border\":\"none\",\"boxShadow\":\"none\",\"opacity\":\"1\"},\"animation\":\"\",\"animationDelay\":\"0\",\"hideOnDesktop\":false,\"hideOnTablet\":false,\"hideOnMobile\":false,\"aiName\":\"Mission Heading\",\"node_id\":\"ai-heading-mission-1\"},\"displayName\":\"Heading\",\"custom\":{},\"parent\":\"ai-section-mission-1__section-inner\",\"hidden\":false,\"nodes\":[],\"linkedNodes\":{}},\"ai-text-mission-1\":{\"type\":{\"resolvedName\":\"TextBlock\"},\"isCanvas\":false,\"props\":{\"text\":\"We believe in honesty, quality, and putting people first. Every brand under the OLS Digital name is expected to uphold these same values in how they serve their customers.\",\"style\":{\"fontSize\":\"16px\",\"lineHeight\":\"1.6\",\"color\":\"#3f3f46\",\"letterSpacing\":\"\",\"textTransform\":\"\",\"fontStyle\":\"\",\"textDecoration\":\"\",\"marginTop\":\"\",\"marginRight\":\"\",\"marginBottom\":\"\",\"marginLeft\":\"\",\"paddingTop\":\"\",\"paddingRight\":\"\",\"paddingBottom\":\"\",\"paddingLeft\":\"\",\"border\":\"none\",\"boxShadow\":\"none\",\"opacity\":\"1\"},\"animation\":\"\",\"animationDelay\":\"0\",\"hideOnDesktop\":false,\"hideOnTablet\":false,\"hideOnMobile\":false,\"aiName\":\"Mission Text\",\"node_id\":\"ai-text-mission-1\"},\"displayName\":\"Text\",\"custom\":{},\"parent\":\"ai-section-mission-1__section-inner\",\"hidden\":false,\"nodes\":[],\"linkedNodes\":{}},\"ai-section-mission-1__section-inner\":{\"type\":{\"resolvedName\":\"Container\"},\"isCanvas\":true,\"props\":{\"style\":{\"padding\":\"20px\",\"minHeight\":\"100px\",\"justifyContent\":\"\",\"marginTop\":\"\",\"marginRight\":\"\",\"marginBottom\":\"\",\"marginLeft\":\"\",\"paddingTop\":\"\",\"paddingRight\":\"\",\"paddingBottom\":\"\",\"paddingLeft\":\"\",\"border\":\"none\",\"boxShadow\":\"none\",\"opacity\":\"1\"},\"tag\":\"div\",\"fullWidth\":false,\"contentWidth\":\"full\",\"anchorId\":\"\",\"cssId\":\"\",\"cssClass\":\"\",\"animation\":\"\",\"animationDelay\":\"0\",\"hideOnDesktop\":false,\"hideOnTablet\":false,\"hideOnMobile\":false},\"displayName\":\"Container\",\"custom\":{},\"parent\":\"ai-section-mission-1\",\"hidden\":false,\"nodes\":[\"ai-heading-mission-1\",\"ai-text-mission-1\"],\"linkedNodes\":{}},\"ai-cta-about-1\":{\"type\":{\"resolvedName\":\"CTASection\"},\"isCanvas\":false,\"props\":{\"heading\":\"Have Questions?\",\"description\":\"We'd love to hear from you.\",\"ctas\":[{\"text\":\"Email info@olsdigital.com\",\"href\":\"mailto:info@olsdigital.com\",\"variant\":\"primary\"}],\"gradient\":\"linear-gradient(135deg, #2563eb 0%, #7c3aed 100%)\",\"anchorId\":\"about-contact\",\"style\":{},\"animation\":\"\",\"animationDelay\":\"\",\"hideOnDesktop\":false,\"hideOnTablet\":false,\"hideOnMobile\":false,\"aiName\":\"About CTA\",\"node_id\":\"ai-cta-about-1\"},\"displayName\":\"CTA Section\",\"custom\":{},\"parent\":\"ROOT\",\"hidden\":false,\"nodes\":[],\"linkedNodes\":{}},\"ROOT\":{\"type\":{\"resolvedName\":\"Container\"},\"isCanvas\":true,\"props\":{\"style\":{\"padding\":\"20px\",\"minHeight\":\"100px\",\"justifyContent\":\"\",\"marginTop\":\"\",\"marginRight\":\"\",\"marginBottom\":\"\",\"marginLeft\":\"\",\"paddingTop\":\"\",\"paddingRight\":\"\",\"paddingBottom\":\"\",\"paddingLeft\":\"\",\"border\":\"none\",\"boxShadow\":\"none\",\"opacity\":\"1\"},\"tag\":\"div\",\"fullWidth\":false,\"contentWidth\":\"full\",\"anchorId\":\"\",\"cssId\":\"\",\"cssClass\":\"\",\"animation\":\"\",\"animationDelay\":\"0\",\"hideOnDesktop\":false,\"hideOnTablet\":false,\"hideOnMobile\":false,\"aiName\":\"Root\",\"node_id\":\"ai-root-about\"},\"displayName\":\"Container\",\"custom\":{},\"parent\":null,\"hidden\":false,\"nodes\":[\"ai-hero-about-1\",\"ai-section-about-1\",\"ai-section-mission-1\",\"ai-cta-about-1\"],\"linkedNodes\":{}}}" + }, + { + "id": "page_mtxec41h_3", + "name": "Contact", + "slug": "contact", + "craftState": "{\"ai-hero-contact-1\":{\"type\":{\"resolvedName\":\"HeroSimple\"},\"isCanvas\":false,\"props\":{\"heading\":\"Contact Us\",\"subtitle\":\"Have a question about OLS Digital or one of our brands? We're happy to help.\",\"ctas\":[],\"bgType\":\"gradient\",\"bgColor\":\"#1e293b\",\"bgGradientFrom\":\"#0f172a\",\"bgGradientTo\":\"#334155\",\"bgGradientAngle\":135,\"bgImage\":\"\",\"bgVideo\":\"\",\"overlayColor\":\"#000000\",\"overlayOpacity\":0,\"textColor\":\"#ffffff\",\"buttonBgColor\":\"#3b82f6\",\"buttonTextColor\":\"#ffffff\",\"minHeight\":\"40vh\",\"verticalAlign\":\"center\",\"textAlign\":\"center\",\"anchorId\":\"contact\",\"style\":{},\"aiName\":\"Contact Hero\",\"node_id\":\"ai-hero-contact-1\"},\"displayName\":\"Hero\",\"custom\":{},\"parent\":\"ROOT\",\"hidden\":false,\"nodes\":[],\"linkedNodes\":{}},\"ai-section-contact-1\":{\"type\":{\"resolvedName\":\"Section\"},\"isCanvas\":false,\"props\":{\"style\":{\"paddingTop\":\"60px\",\"paddingBottom\":\"60px\",\"textAlign\":\"center\"},\"innerMaxWidth\":\"1200px\",\"topDivider\":\"none\",\"topDividerColor\":\"#ffffff\",\"topDividerHeight\":\"50px\",\"bottomDivider\":\"none\",\"bottomDividerColor\":\"#ffffff\",\"bottomDividerHeight\":\"50px\",\"anchorId\":\"contact-info\",\"animation\":\"\",\"animationDelay\":\"0\",\"hideOnDesktop\":false,\"hideOnTablet\":false,\"hideOnMobile\":false,\"aiName\":\"Contact Info\",\"node_id\":\"ai-section-contact-1\"},\"displayName\":\"Section\",\"custom\":{},\"parent\":\"ROOT\",\"hidden\":false,\"nodes\":[],\"linkedNodes\":{\"section-inner\":\"ai-section-contact-1__section-inner\"}},\"ai-heading-contact-1\":{\"type\":{\"resolvedName\":\"Heading\"},\"isCanvas\":false,\"props\":{\"text\":\"Get In Touch\",\"level\":\"h2\",\"style\":{\"fontSize\":\"36px\",\"fontWeight\":\"700\",\"fontFamily\":\"Inter, sans-serif\",\"color\":\"#1f2937\",\"marginBottom\":\"16px\",\"lineHeight\":\"\",\"letterSpacing\":\"\",\"textTransform\":\"\",\"fontStyle\":\"\",\"textDecoration\":\"\",\"marginTop\":\"\",\"marginRight\":\"\",\"marginLeft\":\"\",\"paddingTop\":\"\",\"paddingRight\":\"\",\"paddingBottom\":\"\",\"paddingLeft\":\"\",\"border\":\"none\",\"boxShadow\":\"none\",\"opacity\":\"1\"},\"animation\":\"\",\"animationDelay\":\"0\",\"hideOnDesktop\":false,\"hideOnTablet\":false,\"hideOnMobile\":false,\"aiName\":\"Contact Heading\",\"node_id\":\"ai-heading-contact-1\"},\"displayName\":\"Heading\",\"custom\":{},\"parent\":\"ai-section-contact-1__section-inner\",\"hidden\":false,\"nodes\":[],\"linkedNodes\":{}},\"ai-text-contact-1\":{\"type\":{\"resolvedName\":\"TextBlock\"},\"isCanvas\":false,\"props\":{\"text\":\"For all inquiries regarding OLS Digital, AnHonestHost, StreamerTools, or any of our other brands, please reach out via email and our team will respond as soon as possible.\",\"style\":{\"fontSize\":\"16px\",\"lineHeight\":\"1.6\",\"color\":\"#3f3f46\",\"letterSpacing\":\"\",\"textTransform\":\"\",\"fontStyle\":\"\",\"textDecoration\":\"\",\"marginTop\":\"\",\"marginRight\":\"\",\"marginBottom\":\"\",\"marginLeft\":\"\",\"paddingTop\":\"\",\"paddingRight\":\"\",\"paddingBottom\":\"\",\"paddingLeft\":\"\",\"border\":\"none\",\"boxShadow\":\"none\",\"opacity\":\"1\"},\"animation\":\"\",\"animationDelay\":\"0\",\"hideOnDesktop\":false,\"hideOnTablet\":false,\"hideOnMobile\":false,\"aiName\":\"Contact Text\",\"node_id\":\"ai-text-contact-1\"},\"displayName\":\"Text\",\"custom\":{},\"parent\":\"ai-section-contact-1__section-inner\",\"hidden\":false,\"nodes\":[],\"linkedNodes\":{}},\"ai-spacer-contact-1\":{\"type\":{\"resolvedName\":\"Spacer\"},\"isCanvas\":false,\"props\":{\"height\":\"20px\",\"style\":{},\"aiName\":\"Spacer\",\"node_id\":\"ai-spacer-contact-1\"},\"displayName\":\"Spacer\",\"custom\":{},\"parent\":\"ai-section-contact-1__section-inner\",\"hidden\":false,\"nodes\":[],\"linkedNodes\":{}},\"ai-button-contact-1\":{\"type\":{\"resolvedName\":\"ButtonLink\"},\"isCanvas\":false,\"props\":{\"text\":\"info@olsdigital.com\",\"href\":\"mailto:info@olsdigital.com\",\"target\":\"_self\",\"hoverBg\":\"\",\"hoverColor\":\"\",\"style\":{\"backgroundColor\":\"#3b82f6\",\"color\":\"#ffffff\",\"padding\":\"12px 24px\",\"borderRadius\":\"8px\",\"fontWeight\":\"600\",\"fontSize\":\"16px\",\"border\":\"none\",\"marginTop\":\"\",\"marginRight\":\"\",\"marginBottom\":\"\",\"marginLeft\":\"\",\"boxShadow\":\"none\",\"opacity\":\"1\"},\"animation\":\"\",\"animationDelay\":\"0\",\"hideOnDesktop\":false,\"hideOnTablet\":false,\"hideOnMobile\":false,\"aiName\":\"Email Button\",\"node_id\":\"ai-button-contact-1\"},\"displayName\":\"Button\",\"custom\":{},\"parent\":\"ai-section-contact-1__section-inner\",\"hidden\":false,\"nodes\":[],\"linkedNodes\":{}},\"ai-section-contact-1__section-inner\":{\"type\":{\"resolvedName\":\"Container\"},\"isCanvas\":true,\"props\":{\"style\":{\"padding\":\"20px\",\"minHeight\":\"100px\",\"justifyContent\":\"\",\"marginTop\":\"\",\"marginRight\":\"\",\"marginBottom\":\"\",\"marginLeft\":\"\",\"paddingTop\":\"\",\"paddingRight\":\"\",\"paddingBottom\":\"\",\"paddingLeft\":\"\",\"border\":\"none\",\"boxShadow\":\"none\",\"opacity\":\"1\"},\"tag\":\"div\",\"fullWidth\":false,\"contentWidth\":\"full\",\"anchorId\":\"\",\"cssId\":\"\",\"cssClass\":\"\",\"animation\":\"\",\"animationDelay\":\"0\",\"hideOnDesktop\":false,\"hideOnTablet\":false,\"hideOnMobile\":false},\"displayName\":\"Container\",\"custom\":{},\"parent\":\"ai-section-contact-1\",\"hidden\":false,\"nodes\":[\"ai-heading-contact-1\",\"ai-text-contact-1\",\"ai-spacer-contact-1\",\"ai-button-contact-1\"],\"linkedNodes\":{}},\"ROOT\":{\"type\":{\"resolvedName\":\"Container\"},\"isCanvas\":true,\"props\":{\"style\":{\"padding\":\"20px\",\"minHeight\":\"100px\",\"justifyContent\":\"\",\"marginTop\":\"\",\"marginRight\":\"\",\"marginBottom\":\"\",\"marginLeft\":\"\",\"paddingTop\":\"\",\"paddingRight\":\"\",\"paddingBottom\":\"\",\"paddingLeft\":\"\",\"border\":\"none\",\"boxShadow\":\"none\",\"opacity\":\"1\"},\"tag\":\"div\",\"fullWidth\":false,\"contentWidth\":\"full\",\"anchorId\":\"\",\"cssId\":\"\",\"cssClass\":\"\",\"animation\":\"\",\"animationDelay\":\"0\",\"hideOnDesktop\":false,\"hideOnTablet\":false,\"hideOnMobile\":false,\"aiName\":\"Root\",\"node_id\":\"ai-root-contact\"},\"displayName\":\"Container\",\"custom\":{},\"parent\":null,\"hidden\":false,\"nodes\":[\"ai-hero-contact-1\",\"ai-section-contact-1\"],\"linkedNodes\":{}}}" + } + ], + "head_code": "", + "design": { + "primaryColor": "#3b82f6", + "secondaryColor": "#8b5cf6", + "accentColor": "#10b981", + "headingFont": "Inter, sans-serif", + "bodyFont": "Inter, sans-serif", + "linkColor": "#3b82f6", + "successColor": "#10b981", + "warningColor": "#f59e0b", + "errorColor": "#ef4444", + "backgroundColor": "#ffffff", + "textColor": "#1f2937", + "mutedTextColor": "#6b7280", + "borderColor": "#e5e7eb", + "borderRadius": "8px", + "buttonFont": "Inter, sans-serif", + "buttonRadius": "8px", + "navStyle": "light", + "headCode": "", + "favicon": "" + }, + "extras": [], + "_rev": "0af66cc775393317", + "_base_rev": "3d18b0567d28ea29", + "_client_id": "e4633813-f672-4fbb-9618-d16fb97ff90f" +} \ No newline at end of file diff --git a/craft/tests/fixtures/canvas-parity/ols.spec.json b/craft/tests/fixtures/canvas-parity/ols.spec.json new file mode 100644 index 0000000..946fb6d --- /dev/null +++ b/craft/tests/fixtures/canvas-parity/ols.spec.json @@ -0,0 +1,6 @@ +{ + "name": "ols", + "project": "ols.project.json", + "published": {"index": "ols.index.html", "about": "ols.about.html", "contact": "ols.contact.html"}, + "_note": "brands is deliberately not listed: its ColumnLayout row renders differently in the canvas than the export (padding longhand / wrapping) -- a component bug unrelated to the base reset" +}