Tortusfor Designers

Design tokens

Every CSS variable a Tortus site exposes — color, type, spacing, motion, loader, navigation, and widget skins.

Every published Tortus site (and the builder canvas) carries a full set of CSS custom properties emitted from the org's brand. Reference them in any Custom Code block or converted section, and your work stays on‑brand and consistent, and re‑skins automatically if the broker changes their brand.

Source of truth: @tortus/design-tokens (toModularCssVars). Override any value per‑site via the brand's design_tokens — tell us the values and every page picks them up.

Color

VariableDefault
--color-primary#27323aprimary brand
--color-secondary#4a5f7fsecondary
--color-accent#27323aaccent / CTAs
--color-primary-rgb · --color-secondary-rgb · --color-accent-rgb"R G B"triplets for color-mix() / opacity
--color-background#FFFFFFpage background
--color-background-alt#F5F5F5alt surface
--color-text#1A1A1Abody text
--color-text-secondary#666666muted text
--color-text-inverse#FFFFFFon‑dark text
--color-border#E5E5E5borders
--color-success / --color-warning / --color-error / --color-info#10B981 / #F59E0B / #EF4444 / #3B82F6status

Background is page/section only — it does not color buttons. A block's background (the backgroundColor role, or --color-background) sets the surface behind the content. Button fills come from --color-accent (the "CTAs" color) or the block's own button-style controls (buttonColor / buttonColorCustom).

Typography

VariableDefault
--font-family-heading'Playfair Display', 'Cormorant', Georgia, serif
--font-family-body'Inter', 'SF Pro Display', system-ui, sans-serif
--font-size-xs … --font-size-5xl0.75rem4rem
--font-weight-light … --font-weight-bold300700
--line-height-tight / -normal / -relaxed1.25 / 1.5 / 1.75
--letter-spacing-tight / -normal / -wide-0.025em / 0 / 0.1em

Spacing · radius · shadow

GroupVariablesRange
Spacing--space-0 … --space-120030rem
Radius--radius-none / -sm / -md / -lg / -xl / -full09999px
Shadow--shadow-none / -sm / -md / -lg / -xl / -2xlflat → deep

Motion

Durations + easing curves + scroll/parallax/hover primitives. Animate against these so motion is consistent and on‑brand.

VariableDefaultUse for
--motion-duration-instant0mssnap states
--motion-duration-fast150mshovers, toggles
--motion-duration-normal300msmost transitions
--motion-duration-slow500mssection reveals
--motion-duration-slower800mshero / preloader
--motion-easing-standardcubic-bezier(0.4, 0, 0.2, 1)general UI
--motion-easing-deceleratecubic-bezier(0, 0, 0.2, 1)enter / reveal‑in
--motion-easing-acceleratecubic-bezier(0.4, 0, 1, 1)exit / fade‑out
--motion-easing-emphasizedcubic-bezier(0.2, 0, 0, 1)expressive
--motion-easing-springcubic-bezier(0.34, 1.56, 0.64, 1)playful overshoot
--motion-parallax-depth0.15parallax translate multiplier
--motion-scroll-reveal-distance24pxreveal‑in rise distance
--motion-hover-lift-4pxtranslateY on hover
.reveal { opacity: 0; transform: translateY(var(--motion-scroll-reveal-distance));
  transition: opacity var(--motion-duration-slow) var(--motion-easing-decelerate),
              transform var(--motion-duration-slow) var(--motion-easing-decelerate); }
.reveal.in-view { opacity: 1; transform: none; }
.card:hover { transform: translateY(var(--motion-hover-lift));
  transition: transform var(--motion-duration-fast) var(--motion-easing-standard); }

Art direction motion vars

Two extra motion vars are set per site by the art direction + motion level the site was built with. Unlike the tokens above they don't come from @tortus/design-tokens — they're injected as a managed :root{…} block in the site's Custom CSS at build time. Read them in your own motion so a parallax or reveal you hand‑write moves at the SAME intensity as the rest of the site, and re‑tunes for free if the direction or motion level changes.

VariableSet byUse for
--parallax-speedart direction × motion levelthe parallax drift multiplier the platform's hero/showcase parallax uses — multiply your own scroll‑linked transforms by it so they match (Bold drives hard, Editorial drifts, Minimal near‑still; Still motion → 0)
--tr-durart directionscroll‑reveal / entrance duration (ms) — drop straight into a transition
/* a reveal that lasts exactly as long as the site's direction intends */
.reveal { opacity: 0; transform: translateY(var(--motion-scroll-reveal-distance));
  transition: opacity var(--tr-dur, 760ms) var(--motion-easing-decelerate),
              transform var(--tr-dur, 760ms) var(--motion-easing-decelerate); }
.reveal.in-view { opacity: 1; transform: none; }

Both carry safe fallbacks, so a block that reads them still works on a site with no direction set (the editor, or a legacy site).

Loader / preloader

The page‑load + route‑transition spinner. Colors follow the brand by default.

VariableDefault
--loader-spinner-colorvar(--color-accent)
--loader-spinner-track-colorvar(--color-border)
--loader-spinner-size40px
--loader-spinner-thickness3px
--loader-spinner-duration0.8s
--loader-spinner-easinglinear
--loader-overlay-colorvar(--color-background)
--loader-overlay-blur8px
.preloader { position: fixed; inset: 0; display: grid; place-items: center;
  background: var(--loader-overlay-color); backdrop-filter: blur(var(--loader-overlay-blur)); }
.preloader__spinner { width: var(--loader-spinner-size); height: var(--loader-spinner-size);
  border: var(--loader-spinner-thickness) solid var(--loader-spinner-track-color);
  border-top-color: var(--loader-spinner-color); border-radius: 50%;
  animation: spin var(--loader-spinner-duration) var(--loader-spinner-easing) infinite; }
@keyframes spin { to { transform: rotate(360deg); } }

Widget skins

Backend‑fed widgets follow your brand for backgrounds/type/text already; these are the small extra accents you can recolor.

VariableDefaultDrives
--rating-star-filled#FBBF24filled review stars
--rating-star-empty#D1D5DBempty review stars
--instagram-overlayrgba(0, 0, 0, 0.6)hover scrim over Instagram tiles
:root { --rating-star-filled: var(--color-accent); }  /* brand-colored stars */

The hover sub‑menu on the site navigation reads its own token group, derived from the core palette (so a brand change re‑skins it for free) but namespaced so you can restyle the menu surface independently of the page background. Every NavigationHeader variant reads these, so it's a one‑place change.

VariableDefaultDrives
--nav-dropdown-bgvar(--color-background) (#FFFFFF)dropdown surface
--nav-dropdown-fgvar(--color-text) (#1A1A1A)menu item text
--nav-dropdown-hover-bgrgba(<primary-rgb> / 0.06)hovered item background
--nav-dropdown-bordervar(--color-border) (#E5E5E5)dropdown border
--nav-dropdown-shadowvar(--shadow-xl)dropdown elevation
/* a darker, tighter sub-menu without touching the page background */
:root {
  --nav-dropdown-bg: var(--color-primary);
  --nav-dropdown-fg: var(--color-text-inverse);
  --nav-dropdown-hover-bg: rgba(var(--color-accent-rgb) / 0.14);
}

The consent banner reads its own --banner-* token group so a broker can re‑skin the banner chrome without touching the page. Every value is a per‑site override (organizations.settings.cookie_banner.tokens); blank inherits the platform default below (and, for --banner-primary-bg + --banner-rail, the brand accent when one is set). The legal copy is fixed by compliance — these govern only the chrome. Value spec: @tortus/design-tokens (complianceBannerTokens).

VariableDefaultDrives
--banner-surface#ffffffcard background
--banner-ink#27323atitle / heading text
--banner-muted#5b6770body / description text
--banner-borderrgba(39,50,58,0.10)card border
--banner-rail#6fd8bathin brand rail along the top edge
--banner-accent#6fd8bacategory toggles / links / focus
--banner-primary-bg#27323a"Accept all" button background
--banner-primary-ink#ffffff"Accept all" button text
--banner-radius0.75remcard corner radius
--banner-button-radius0.5rembutton corner radius
/* a tighter, brand-forward banner */
:root {
  --banner-primary-bg: var(--color-accent);
  --banner-rail: var(--color-accent);
  --banner-radius: 20px;
  --banner-button-radius: 999px;
}

For deeper restyling than these tokens allow, the banner also exposes the .tortus-cookie-banner / .tortus-cookie-accept / .tortus-cookie-reject class hooks and a scoped Custom CSS field — see Cookie banner.

The design page

In the builder, the Design surface is where you mark up a page and drop in {{tortus:…}} modules (compliant search/listings, plus backend‑fed team, blog, reviews, Instagram, new developments, and the market surfaces — neighborhood index, published reports, live market data, neighborhood report, and place momentum). Those modules render our data inside your markup; the tokens above style everything around (and, where noted, within) them. See the Designer handbook for the module reference, the compliance rules, and the full workflow.