/* Enactor thought piece — scoped styles. Safe to sit alongside Avada Global Options. */ .ei { /* --- Font families: each Axiforma weight is its own family in Avada --- */ --ei-f-xb: axiformaextrabold, "Montserrat", "Helvetica Neue", Arial, sans-serif; --ei-f-light: axiformalight, "Montserrat", "Helvetica Neue", Arial, sans-serif; --ei-f-semi: axiformasemibold, "Montserrat", "Helvetica Neue", Arial, sans-serif; --ei-f-med: axiformamedium, "Montserrat", "Helvetica Neue", Arial, sans-serif; /* --- Brand colours --- */ --ei-blue-black: #212A34; --ei-deep-blue: #3A4C5E; --ei-dark-blue: #008BBB; --ei-light-blue: #4AC0E7; --ei-carmine: #DE6778; --ei-iceberg: #ECF5FC; --ei-alt: #F9F9F9; --ei-border: #DADADA; box-sizing: border-box; } .ei *, .ei *::before, .ei *::after { box-sizing: border-box; } /* Reset only inside our wrapper, so Avada's global type doesn't leak in */ .ei h1, .ei h2, .ei h3, .ei p, .ei ul, .ei li, .ei figure, .ei blockquote { margin: 0; padding: 0; text-transform: none; } .ei h1, .ei h2, .ei h3 { font-family: var(--ei-f-xb); font-weight: normal; } .ei p, .ei li { font-family: var(--ei-f-light); font-weight: normal; } .ei a { text-decoration: none; transition: color 160ms cubic-bezier(.4,0,.2,1), border-color 160ms cubic-bezier(.4,0,.2,1); } .ei img { max-width: 100%; height: auto; display: block; } .ei :focus-visible { outline: 2px solid var(--ei-light-blue); outline-offset: 2px; } /* ---------- HERO ---------- */ .ei-hero { position: relative; overflow: hidden; margin: clamp(10px, 1.4vw, 18px); border-radius: clamp(22px, 2.8vw, 40px); background: var(--ei-blue-black) center/cover no-repeat; } .ei-hero__wash { position: absolute; inset: 0; background: linear-gradient(150deg, rgba(33,42,52,.94) 0%, rgba(33,42,52,.82) 42%, rgba(0,139,187,.55) 100%); } .ei-hero__line { position: absolute; top: -20%; width: 46%; height: 140%; transform: rotate(14deg); } .ei-hero__line--a { right: -6%; border-left: 1px solid rgba(222,103,120,.55); } .ei-hero__line--b { right: 4%; border-left: 1px solid rgba(74,192,231,.40); } .ei-hero__inner { position: relative; max-width: 1280px; margin: 0 auto; padding: clamp(28px,4vw,44px) clamp(20px,5vw,40px) clamp(52px,7vw,96px); display: grid; gap: clamp(28px,4vw,44px); } .ei-eyebrow { display: flex; align-items: center; gap: 14px; padding-top: 10px; } .ei-eyebrow span { font-family: var(--ei-f-xb); font-size: 15px; line-height: 1; letter-spacing: .12em; text-transform: uppercase; color: var(--ei-light-blue); } .ei-hero h1 { font-size: clamp(34px, 4.4vw, 62px); line-height: 1.06; letter-spacing: -.025em; color: #FFFFFF; text-wrap: balance; } .ei-hero h1 em { font-style: normal; color: #FFFFFF; } .ei-meta { display: flex; flex-wrap: wrap; align-items: center; gap: clamp(16px,3vw,40px); border-top: 1px solid rgba(255,255,255,.18); padding-top: clamp(18px,2.4vw,26px); } .ei-meta__i { display: grid; gap: 3px; } .ei-meta__i b { font-family: var(--ei-f-semi); font-weight: normal; font-size: 15px; line-height: 1.3; color: #FFFFFF; } .ei-meta__i span { font-family: var(--ei-f-light); font-size: 14px; line-height: 1.3; color: rgba(255,255,255,.7); } .ei-meta__rule { width: 1px; height: 34px; background: var(--ei-carmine); } /* ---------- SIDE RAIL ---------- */ .ei-rail { display: grid; gap: 20px; align-content: start; } .ei-rail__label { font-family: var(--ei-f-xb); font-size: 12px; line-height: 1; letter-spacing: .12em; text-transform: uppercase; color: var(--ei-dark-blue); } .ei-toc { display: grid; gap: 2px; border-left: 1px solid var(--ei-border); } .ei-toc a { display: block; padding: 9px 0 9px 16px; margin-left: -1px; border-left: 2px solid transparent; font-family: var(--ei-f-light); font-size: 14px; line-height: 1.45; color: var(--ei-deep-blue); } .ei-toc a:hover { color: var(--ei-blue-black); } .ei-toc a.is-active { border-left-color: var(--ei-dark-blue); font-family: var(--ei-f-semi); color: var(--ei-blue-black); } .ei-rail__group { border-top: 1px solid var(--ei-border); padding-top: 20px; display: grid; gap: 12px; } .ei-rail__group > p { font-size: 14px; line-height: 1.55; color: var(--ei-deep-blue); } .ei-rail__group > b { font-family: var(--ei-f-semi); font-weight: normal; font-size: 14px; line-height: 1.4; color: var(--ei-blue-black); } .ei-share { display: flex; align-items: center; gap: 10px; } .ei-share a { width: 40px; height: 40px; border: 1px solid var(--ei-border); display: grid; place-items: center; border-radius: 999px; color: var(--ei-dark-blue); } .ei-share a:hover { border-color: var(--ei-dark-blue); } /* Buttons */ .ei-btn { display: inline-flex; align-items: center; justify-content: center; font-family: var(--ei-f-semi); font-weight: normal; border-radius: 14px; background: var(--ei-dark-blue); color: #FFFFFF !important; border: 1px solid var(--ei-dark-blue); } .ei-btn:hover { background: var(--ei-deep-blue); border-color: var(--ei-deep-blue); color: #FFFFFF !important; } .ei-btn--sm { padding: 12px 20px; font-size: 14px; } .ei-btn--lg { padding: 18px 30px; font-size: 16px; } .ei-btn--outline { background: transparent; color: var(--ei-dark-blue) !important; } .ei-btn--outline:hover { background: var(--ei-dark-blue); color: #FFFFFF !important; } /* ---------- ARTICLE ---------- */ .ei-article { display: grid; gap: clamp(30px,4vw,44px); max-width: 74ch; } .ei-stand { font-size: clamp(20px,2vw,25px); line-height: 1.5; color: var(--ei-blue-black); text-wrap: pretty; } .ei-prose { display: grid; gap: 22px; } .ei-prose p, .ei-body { font-size: clamp(17px,1.35vw,19px); line-height: 1.68; color: var(--ei-blue-black); text-wrap: pretty; } .ei-sec { display: grid; gap: 22px; scroll-margin-top: 120px; } .ei-sec h2 { font-size: clamp(26px,2.8vw,36px); line-height: 1.15; letter-spacing: -.02em; color: var(--ei-blue-black); } .ei-steps { display: grid; gap: clamp(12px,1.6vw,16px); } .ei-step { border: 1px solid var(--ei-border); border-radius: clamp(16px,1.8vw,22px); padding: clamp(22px,2.6vw,30px); display: grid; grid-template-columns: 44px minmax(0,1fr); gap: clamp(16px,2vw,24px); align-items: start; } .ei-step > span { font-family: var(--ei-f-xb); font-size: clamp(22px,2.2vw,28px); line-height: 1; color: var(--ei-light-blue); } .ei-step h3 { font-size: clamp(19px,1.8vw,23px); line-height: 1.25; color: var(--ei-blue-black); } .ei-step p { font-size: 16px; line-height: 1.62; color: var(--ei-deep-blue); margin-top: 10px; } /* Avada resets figure padding/margin, so these are forced. */ .ei figure.ei-quote { border: 1px solid var(--ei-border) !important; border-radius: clamp(16px,1.8vw,22px); padding: clamp(24px,2.8vw,32px) !important; margin: 0 !important; display: grid; gap: clamp(22px,2.6vw,28px); box-sizing: border-box; } .ei .ei-quote__body { display: grid; gap: 14px; justify-items: start; } .ei .ei-quote__body img { width: 34px; height: auto; display: block; } .ei .ei-quote__body p { font-family: var(--ei-f-light); font-size: clamp(19px,1.7vw,22px); line-height: 1.6; color: var(--ei-blue-black); font-style: normal; } .ei-quote figcaption { display: flex; align-items: center; gap: 18px; } .ei-quote figcaption img { width: 72px; height: 72px; border-radius: 999px; object-fit: cover; flex: none; } .ei-quote__who { display: grid; gap: 4px; } .ei-quote__who b { font-family: var(--ei-f-semi); font-weight: normal; font-size: 16px; line-height: 1.4; color: var(--ei-blue-black); } .ei-quote__who span { font-family: var(--ei-f-light); font-size: 15px; line-height: 1.4; color: var(--ei-deep-blue); } /* ---------- CTA ---------- */ .ei-cta { margin: clamp(10px,1.4vw,18px); border-radius: clamp(22px,2.8vw,40px); overflow: hidden; background: var(--ei-iceberg); } .ei-cta__inner { max-width: 1280px; margin: 0 auto; padding: clamp(44px,6vw,88px) clamp(20px,5vw,40px); display: grid; grid-template-columns: repeat(auto-fit, minmax(300px,1fr)); gap: clamp(28px,4vw,56px); align-items: center; } .ei-cta h2 { font-size: clamp(26px,3.2vw,42px); line-height: 1.1; letter-spacing: -.02em; color: var(--ei-blue-black); max-width: 20ch; } .ei-cta h2 em { font-style: normal; color: var(--ei-carmine); } .ei-cta p { font-size: 17px; line-height: 1.65; color: var(--ei-deep-blue); max-width: 46ch; margin-top: 18px; } .ei-cta__actions { display: flex; flex-wrap: wrap; gap: 14px; justify-content: flex-end; } @media (max-width: 782px) { .ei-cta__actions { justify-content: flex-start; } } /* --------------------------------------------------------------- PATCH — centre the whole article layout (rail + text together) PREFERRED FIX IS AN AVADA SETTING, NOT CSS: Container 2 → Width → set to "Site Width" (not "100% Width"). That caps and centres the row natively. If you do that, you can delete this whole PATCH 1 block and keep only PATCH 2 below. Use the CSS below only if Container 2 must stay 100% Width. Requires CSS Class "ei-container" on Container 2. --------------------------------------------------------------- */ .ei-container .fusion-builder-row, .ei-container .fusion-row, .ei-container > .fusion-builder-row-container, .ei-container > div:first-child { max-width: 1280px !important; margin-left: auto !important; margin-right: auto !important; float: none !important; } /* The rail and the article both sit flush-left in their own columns; the centring is done by the row above, not by the article. */ .ei .ei-article { margin-left: 0; margin-right: 0; } /* --------------------------------------------------------------- PATCH 2 — clear the sticky header when jumping to a section --------------------------------------------------------------- */ .ei .ei-sec { scroll-margin-top: 170px; } .ei .ei-rail { padding-top: 4px; } /* --------------------------------------------------------------- PATCH 3 — kill the theme's 314px top padding on single posts. The site adds it to .post-content > div:first-child for logged-out visitors on screens >=1200px, which shows as a big white gap above the hero. Same selector + !important so only this post is affected. If the header ever renders transparent over the hero, use 20px instead of 0. --------------------------------------------------------------- */ @media only screen and (min-width: 1200px) { body.single.single-post:not(.logged-in) main#main .post-content > div:first-child { padding-top: 0 !important; } } /* --------------------------------------------------------------- PATCH 4 — mobile fixes 1. CTA: stack the buttons beneath the text (the auto-fit grid was keeping two columns and pushing the buttons off-screen). 2. Hero: Avada adds side padding to the container on mobile, which stacked with the hero's own inset margin. Pull the hero out to match the article's text margins. --------------------------------------------------------------- */ @media only screen and (max-width: 640px) { .ei .ei-cta__inner { grid-template-columns: 1fr !important; gap: 28px; padding: 36px 24px; } .ei .ei-cta__actions { justify-content: flex-start; flex-direction: column; align-items: stretch; } .ei .ei-cta__actions .ei-btn { width: 100%; } .ei .ei-cta h2 { max-width: none; } /* Hero: wider, matching the body text gutter */ .ei .ei-hero { margin: 0 -10px; border-radius: 18px; } .ei .ei-hero__inner { padding: 26px 20px 40px; } } /* ---------- Diagrams ---------- */ .ei .ei-fig { margin: 0; display: grid; gap: 14px; } .ei .ei-fig__frame { border: 1px solid var(--ei-border); border-radius: clamp(16px, 1.8vw, 22px); overflow: hidden; } .ei .ei-fig__frame img { display: block; width: 100%; height: auto; } .ei .ei-fig figcaption { font-family: var(--ei-f-light); font-size: 14px; line-height: 1.5; color: var(--ei-deep-blue); font-style: normal; } /* ---------- Progress bar (only visible if the optional JS runs) ---------- */ .ei-progress { position: fixed; top: 0; left: 0; right: 0; height: 3px; z-index: 9999; pointer-events: none; } .ei-progress > div { height: 100%; width: 0; background: var(--ei-dark-blue); transition: width 90ms linear; } /* ---------- Bullet list (carmine rule) ---------- */ .ei .ei-list { display: grid; gap: 14px; list-style: none; margin: 0; padding: 0 0 0 clamp(20px,2.4vw,28px) !important; border-left: 1px solid var(--ei-carmine); } .ei .ei-list li { font-family: var(--ei-f-light); font-size: clamp(16px,1.3vw,18px); line-height: 1.6; color: var(--ei-blue-black); text-wrap: pretty; list-style: none; } /* ---------- Draft placeholders (delete once real images are in) ---------- */ .ei .ei-fig__placeholder { border: 1px dashed var(--ei-border); border-radius: clamp(16px,1.8vw,22px); min-height: clamp(200px,26vw,320px); display: grid; place-items: center; background: var(--ei-alt); padding: 24px; text-align: center; font-family: var(--ei-f-light); font-size: 14px; line-height: 1.5; color: var(--ei-deep-blue); } .ei .ei-quote__ph { width: 72px; height: 72px; border-radius: 999px; border: 1px dashed var(--ei-border); background: var(--ei-alt); flex: none; display: grid; place-items: center; font-family: var(--ei-f-light); font-size: 10px; color: var(--ei-deep-blue); }
The Unlimited Briefing

Build vs buy: what’s the cost of choosing?

Enactor Editorial Thought Leadership
Published 1 October 2026
Read time 6 minutes

Every platform decision in retail tech eventually gets reduced to the same two words: build, or buy. Buy gets you speed and a vendor’s roadmap. Build gets you exactly what your business needs and a maintenance burden nobody budgeted for. Most retailers pick one, live with its trade-off for a decade, and quietly envy whichever one they didn’t choose.

It’s worth asking why this is treated as a single decision at all. A retailer’s platform touches dozens of different jobs: pricing rules, store journeys, loyalty logic, integrations, and a UI a customer actually sees. There’s no law of nature that says all of those jobs have to be resourced the same way. Some of them genuinely are simple enough to configure. Some of them genuinely need a developer. Forcing one answer across all of them is how retailers end up either over-building the easy stuff or under-building the hard stuff.

What buying actually gets you, and costs you

Buying a platform outright is fast. Someone else has already made the decisions, so the retailer inherits a working system rather than assembling one. The cost shows up later, in the form of a system that reflects the vendor’s assumptions about the business rather than the business’s own.

Changing anything meaningful means submitting a request and waiting for the vendor’s roadmap to have room for it. A retailer who has to ask permission to change how their own promotions run isn’t really running their own business.

What building actually gets you, and costs you

Building it yourself solves that problem in the most direct way possible: nothing is inherited, everything reflects the business, because the business built it. The cost is that “built” doesn’t stay finished.

Every piece a retailer builds themselves is now theirs to maintain, forever, including through every future platform upgrade, every security patch, every new integration the rest of the business needs. Build-heavy retailers don’t run out of ambition. They run out of the engineering hours needed to keep maintaining what ambition already built.

Buy vs build shown as two see-saws: buying tips towards speed, building tips towards control.
Both answers solve today’s requirement. They bill for it differently.

Why this doesn’t have to be one answer

Enactor’s platform is built around a simple observation: the “build vs buy” choice is really three different choices wearing one label, because a platform has at least three different kinds of work happening inside it, and each one suits a different level of effort.

Configuration, through Enactor’s Estate Manager

Store journeys, business rules and UI changes a retail operations team can make directly, with permissions set by role, no developer required. This is the “buy” experience: fast, low-effort, no engineering queue.

Extension, through the Enactor Toolkit

A visual, low-code, drag and drop editor where a developer builds genuinely custom logic at defined points in the platform, starting from a library of ready-made building blocks rather than from scratch. This is the “build” experience, but without the maintenance trap of a full custom build, because the logic sits where the platform was designed to receive it, not buried inside code the next upgrade has to fight past.

UI development, independently again

Enactor’s own page rendering runs on React, decoupled from the business logic beneath it, so a retailer’s front-end team can shape what customers actually see without touching how a sale gets processed underneath.

None of this requires picking a side. A retailer can configure the bulk of their estate that’s genuinely standard, and reserve real engineering effort for the parts that actually differentiate the business, which is usually where it was needed all along.

Three sliders from less to more effort: Configure needs the least effort, Extend more, Experience the most.
One platform, three levels of effort. Set the level per job, not one level for all.

Why this is a question of limits, not features

This is where platforms genuinely separate from one another: not in the length of their feature lists, but in whether configuration and custom development work together or force a choice between them. A platform that assumes retailers only need one lever will always ask them to pick one.

Don’t limit yourself to build or buy. The retailers getting the most out of their platform right now aren’t the ones who built everything, or the ones who bought everything. They’re the ones whose platform never made them choose in the first place.

Learn More...

Enactor is the Unlimited Unified Commerce platform that lets retailers configure, extend and build, all on the same platform, choosing the right level of effort for each part of the business rather than one level for all of it. Get in touch to see how the Toolkit and Estate Manager work together in practice.

(function () { var bar = document.querySelector('.ei-progress > div'); var links = Array.prototype.slice.call(document.querySelectorAll('.ei-toc a')); var targets = links.map(function (a) { return { link: a, el: document.querySelector(a.getAttribute('href')) }; }).filter(function (t) { return t.el; }); function onScroll() { if (bar) { var max = document.documentElement.scrollHeight - window.innerHeight; var p = max > 0 ? Math.min(1, window.scrollY / max) : 0; bar.style.width = (p * 100).toFixed(2) + '%'; } var active = null; targets.forEach(function (t) { if (t.el.getBoundingClientRect().top <= 160) active = t.link; }); links.forEach(function (a) { a.classList.toggle('is-active', a === active); }); } window.addEventListener('scroll', onScroll, { passive: true }); window.addEventListener('resize', onScroll); onScroll(); // Smooth scroll for the TOC without touching theme behaviour links.forEach(function (a) { a.addEventListener('click', function (e) { var el = document.querySelector(a.getAttribute('href')); if (!el) return; e.preventDefault(); window.scrollTo({ top: el.getBoundingClientRect().top + window.scrollY - 120, behavior: 'smooth' }); }); }); // Copy-link button var copy = document.querySelector('.ei-copy'); if (copy && navigator.clipboard) { copy.addEventListener('click', function (e) { e.preventDefault(); navigator.clipboard.writeText(copy.href); }); } })();