From dc415db2d3d7043635df1653d4004ca2a60eff46 Mon Sep 17 00:00:00 2001 From: Josh Knapp Date: Sun, 1 Nov 2026 08:23:19 -0800 Subject: [PATCH] fix(site-builder): editor canvas renders content with the published base reset Published pages/Preview ship a head reset (*{margin:0;padding:0}, img block, a inherit, body line-height 1.6 / #1f2937 / 16px); the editor canvas had none, so h1-h6/p margins, line-height and inherited size/colour differed. - editor.css: one commented block scoping the reset to .canvas-device-frame, every selector zero-specificity (:where) so inline styles / class rules win exactly as when published; editor chrome untouched (snapshot identical). - tokens.ts: canvas heading/link token rules made zero-specificity too. - utils/css-reset.ts: single source for the reset declarations (html-export imports it; test asserts byte-identity with the backend head and that the editor.css block carries the same declarations). - scripts/e2e-canvas-parity.mjs (npm run test:browser:canvas): real editor vs published HTML in Firefox + Chromium, boxes within 1px + computed styles. Co-Authored-By: Claude Sonnet 5.5 --- craft/package.json | 1 + craft/scripts/e2e-canvas-export-entry.ts | 15 + craft/scripts/e2e-canvas-parity.mjs | 323 ++++++++++++++++++ craft/src/styles/editor.css | 44 +++ craft/src/utils/css-reset.test.ts | 60 ++++ craft/src/utils/css-reset.ts | 21 ++ craft/src/utils/html-export.ts | 3 +- craft/src/utils/tokens.test.ts | 5 +- craft/src/utils/tokens.ts | 10 +- .../fixtures/canvas-parity/ols.about.html | 46 +++ .../fixtures/canvas-parity/ols.brands.html | 54 +++ .../fixtures/canvas-parity/ols.contact.html | 40 +++ .../fixtures/canvas-parity/ols.index.html | 64 ++++ .../fixtures/canvas-parity/ols.project.json | 88 +++++ .../fixtures/canvas-parity/ols.spec.json | 6 + 15 files changed, 774 insertions(+), 6 deletions(-) create mode 100644 craft/scripts/e2e-canvas-export-entry.ts create mode 100644 craft/scripts/e2e-canvas-parity.mjs create mode 100644 craft/src/utils/css-reset.test.ts create mode 100644 craft/src/utils/css-reset.ts create mode 100644 craft/tests/fixtures/canvas-parity/ols.about.html create mode 100644 craft/tests/fixtures/canvas-parity/ols.brands.html create mode 100644 craft/tests/fixtures/canvas-parity/ols.contact.html create mode 100644 craft/tests/fixtures/canvas-parity/ols.index.html create mode 100644 craft/tests/fixtures/canvas-parity/ols.project.json create mode 100644 craft/tests/fixtures/canvas-parity/ols.spec.json diff --git a/craft/package.json b/craft/package.json index f73194d..8572cf9 100644 --- a/craft/package.json +++ b/craft/package.json @@ -11,6 +11,7 @@ "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:canvas": "node scripts/e2e-canvas-parity.mjs", "test:unit:watch": "vitest" }, "dependencies": { 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..9cb7194 --- /dev/null +++ b/craft/scripts/e2e-canvas-parity.mjs @@ -0,0 +1,323 @@ +#!/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. + * + * 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 }); +} + +// A stored `style` often carries a shorthand plus BLANK longhands +// ({padding:'20px', paddingTop:''}). The editor renders those through React, which +// assigns '' to the longhand and thereby wipes the shorthand in the canvas (the +// export drops blanks, so published keeps it). That is a SEPARATE bug from the +// base-reset parity this test guards (same class as fix/bg-shorthand-longhand), so by +// default the blanks are stripped from the loaded state to isolate the reset. +// CANVAS_RAW=1 keeps the stored state verbatim (shows that bug's residue). +function stripBlankStyles(project) { + if (process.env.CANVAS_RAW) return project; + const clean = (json) => { + const nodes = JSON.parse(json); + for (const n of Object.values(nodes)) { + const st = n && n.props && n.props.style; + if (st && typeof st === 'object') for (const k of Object.keys(st)) if (st[k] === '') delete st[k]; + } + return JSON.stringify(nodes); + }; + const out = { ...project }; + for (const k of ['craft_state', 'header_craft_state', 'footer_craft_state']) if (typeof out[k] === 'string' && out[k]) out[k] = clean(out[k]); + out.pages_craft_state = (project.pages_craft_state || []).map((pg) => ({ ...pg, craftState: typeof pg.craftState === 'string' ? clean(pg.craftState) : pg.craftState })); + return out; +} + +// ---------------------------------------------------------------- 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" +}