Everything an implementer needs that the page designs themselves don’t state: breakpoints, the component set with states, motion specifications and the token block.
Responsive
The hero visualisation, the two-sides split and the Vision Path all change form below 768 px rather than scaling down.
≥ 1440
Desktop (primary)
1240 px container, 12 columns, 32 px gutters, 112 px section rhythm.
1024 – 1439
Laptop
Fluid container, 4-up grids become 3-up, display type steps down one level.
768 – 1023
Tablet
Nav collapses to menu button, hero becomes single column, 3-up becomes 2-up.
375 – 767
Mobile
20 px gutters, 72 px section rhythm, one column, 44 px minimum targets.
Component library
Buttons
Hover darkens to #1E3A8A with no lift or scale. The arrow glyph translates 3 px along the V angle on hover.
Badges & feedback
Loading uses the V drawing on a 900 ms loop — never a spinning circle. Skeletons use #F1F5F9 blocks, no shimmer.
Accordion
No. Everything stays in your Odoo database.
Yes — rules and report templates are extensible.
Opens with a 220 ms height transition; the chevron rotates 180°.
Motion documentation
Standard easing is cubic-bezier(.22,.61,.36,1). Everything moves along the 65° V angle. Nothing bounces.
| Element | Trigger | Duration | Movement | Mobile / reduced |
|---|---|---|---|---|
| Vision Path | Scroll position | linked | stroke-dashoffset 1200 → 0, mapped to page progress | Static fully-drawn path |
| Hero data flow | Autoplay loop | 4600ms | Dashed path draws, nodes pulse in sequence at 300 ms offsets | Loop paused, path drawn |
| Hero parallax | Cursor within hero panel | 220ms | ±10 px x, ±8 px y; returns over 420 ms on leave | Disabled (no pointer) |
| Section reveal | 25% in viewport | 420ms | Opacity 0→1, translateY 14 px→0; children stagger 60 ms | Opacity only, no stagger |
| Card hover | Pointer enter | 180ms | Border → #38BDF8; chevron watermark drifts 4 px along 65° | Active state only |
| Button hover | Pointer enter | 120ms | Background → #1E3A8A; arrow glyph +3 px. No lift, no scale | Colour change only |
| Page transition | Route change | 320ms | Outgoing fades; incoming rises 12 px along the vector angle | Instant swap |
| Background vector field | Ambient | 6px/s | Drift along 65°, max opacity 0.25, GPU transform only | Paused |
Developer handoff
1240 px max container, 32 px page gutters (20 px mobile), 12 columns with a 20 px gap. Section vertical rhythm 112 / 96 / 80 / 72 px by breakpoint. Full-bleed sections break the container deliberately — hero background, navy bands and the final CTA.
Backgrounds alternate white → off-white → white → navy. Never two navy sections adjacent, never more than three light sections in a row without a navy band. The footer is always #060B14.
One H1 per page, H2 per section, H3 within. Breadcrumbs on every page below the top level. Product pages carry Product schema, articles carry Article schema, case studies carry CreativeWork.
Target WCAG AA. #38BDF8 never carries text on white — use #2563EB. Body text 16 px minimum, secondary no lighter than #64748B. Every interactive element keyboard-reachable with a visible focus ring; the command palette traps focus and returns it on close.
All motion is SVG stroke and CSS transform — no WebGL, no autoplay video, no canvas. Background graphics are inline SVG. The Vision Path and reading bar share one passive scroll listener.
Logo, monogram, favicon and app icon ship as SVG in /assets. The chevron, vector field and node graphics are inline components, not files. Product screenshots drop into the reserved 16:10 slots on the product page.
--tv-navy: #0B1220; --tv-navy-deep: #060B14; /* footer only */
--tv-navy-blue: #1E3A8A; --tv-blue: #2563EB; --tv-blue-hover: #1D4FD7;
--tv-sky: #38BDF8; --tv-sky-light: #7DD3FC; --tv-sky-pale: #E0F2FE;
--tv-off-white: #F8FAFC; --tv-surface: #F1F5F9; --tv-border: #E2E8F0;
--tv-text: #0B1220; --tv-text-secondary: #475569; --tv-muted: #64748B;
--tv-on-navy: #94A3B8; --tv-success: #059669; --tv-warning: #D97706; --tv-danger: #E11D48;
--tv-container: 1240px; --tv-gutter: 32px; --tv-gutter-mobile: 20px;
--tv-section: 112px; --tv-section-mobile: 72px;
--tv-radius-input: 9px; --tv-radius-card: 16px; --tv-radius-panel: 20px;
--tv-focus-ring: 0 0 0 3px rgb(37 99 235 / .14);
--tv-shadow-lift: 0 24px 60px -30px rgb(11 18 32 / .35);
--tv-ease: cubic-bezier(.22, .61, .36, 1);
--tv-vector-angle: 65deg; /* every motion vector follows this */