Roboto · 12px body v1.0
elluminate Design System
A one-screen tour of the most-used components — listed in production-usage order below. Calm chrome, vibrant data. Roboto, 12px body, 4px radius, 300ms ease. Icons are Font Awesome Light (fal) by default; solid (fas) is reserved for toggled-on / active states.
Angular 12 Bootstrap 4 ng-bootstrap DevExtreme 21 PrimeNG 9 Font Awesome 7 Pro NGXS Chart.js Ace · CodeMirror · Quill angular-gridster2 angular-split
#1F68A8
action
#3B85C7
brand
#182B3B
masthead
#F77623
active rail
#1F8915
success
#EEB12B
warning
#BD341F
error
#1A1A1A
text
#F6F6F6
surface
Buttons (in usage order)
Status
Complete In Review Failed Open Pending Draft Unassigned
Form field
Focus → border becomes #1F68A8
Table
SubjectSiteStatus
SUB-0001Site 12Done
SUB-0002Site 03Review
SUB-0003Site 12Query
Modal
Confirm save
Save changes to Listing 0042?
Risk levels
Low Low-Med High-Med High Extreme
Full reference below

A self-contained preview of the elluminate design tokens and component patterns. Two palettes work together: the calm elluminate chrome and the vibrant Data-Color palette for user-meaningful data. Pair this with design.md for the AI-readable spec.

01 elluminate Palette

Used for all UI chrome (shells, buttons, text, borders). Calm by design — the canvas for vibrant data.

Primary — Blue
blue-100#F0F5FA
blue-200#CADDEE
blue-300#A3C5E2
blue-400#82B0D9
blue-500★#3B85C7
blue-600★#1F68A8
blue-700#215887
blue-800#1E4060
blue-900★#182B3B
★ blue-500 = primary brand · blue-600 = link/text · blue-900 = masthead
Neutral — Gray
white#FFFFFF
gray-100#F6F6F6
gray-200#E8E8E8
gray-300★#DDDDDD
gray-400#BBBBBB
gray-500#767676
gray-600#606060
gray-700#4B4B4B
gray-900★#1A1A1A
★ gray-300 = default border · gray-900 = default text color
Supporting — Green (success)
green-100#EDF6EA
green-200#C0E0B5
green-300#92CA81
green-400#6BB859
green-500★#1F8915
green-600#227817
green-700#206117
green-800#1C4614
green-900#162D11
Supporting — Yellow (warning)
yellow-100#FFF2DE
yellow-200#FDD189
yellow-300★#EEB12B
yellow-400#D49C21
yellow-500#96701D
yellow-600#82601C
yellow-700#634A18
yellow-800#4E3A16
yellow-900#322611
For WCAG-accessible warning text on white, prefer #BC8C24 instead of yellow-300.
Supporting — Red (error)
red-100#FEF1ED
red-200#FACDC2
red-300#F2AA98
red-400#E98E78
red-500#CD482D
red-600★#BD341F
red-700#9C2D1B
red-800#6F2416
red-900#461B11
Supporting — Indigo (information)
indigo-100#F5F2FC
indigo-200#DBD3F3
indigo-300#C0B4EB
indigo-400#A796E4
indigo-500#7466D1
indigo-600#5A52CB
indigo-700★#3F42C5
indigo-800#2C2F94
indigo-900#232059

02 Data-Color Palette

For data visualizations, charts, status colors the user owns, and category coding. Showing the canonical highlight stops (100, 200, 500, 700). Full ramps live in utils/color-palette.scss.

data-red-200#FFCBC0
data-red-500#E6190F
data-orange-200#FFCDAE
data-orange-400★#F77623 active rail
data-yellow-100#FFF4CB
data-yellow-200#FAD50F
data-lime-200#AAEB36
data-lime-500#5E7E25
data-green-200#70F26F
data-green-500#22872A
data-aqua-200#47EEE3
data-aqua-500#21837E
data-blue-200#C8E8FA
data-blue-500#1579C1
data-indigo-200#E0D0FD
data-indigo-600#6648F1
data-violet-200#E7CEFD
data-violet-500#984AF2
data-fuchsia-200#FFC7EC
data-fuchsia-500#D813B0
★ data-orange-400 also serves as the active item rail color across tabs, lists, and selected items.

03 Gradients

Used for buttons, masthead surfaces, and severity bars. Applied as background-image.

Light blue · decorative panel
Soft blue · decorative
Mid blue · decorative
Primary button — default
Primary button — hover / focus
Primary button — active / page toolbar
Danger button — default
Danger button — hover
Deep red · severity bar

04 Typography

Roboto, falling back to Helvetica Neue / Helvetica / Arial. The app is dense — body text is 12px, the heading scale is compressed.

Type scale 4 cols: name · size · line-height · sample
h1 1.9rem 1.2

The quick brown fox

h2 1.1875rem 1.25

The quick brown fox jumps over the lazy dog

h3 1rem 1.25rem

The quick brown fox jumps over the lazy dog

h4 .875rem 1.125rem

The quick brown fox jumps over the lazy dog

h5 .75rem 1.125rem
THE QUICK BROWN FOX JUMPS OVER THE LAZY DOG
h6 .625rem 1.125rem
THE QUICK BROWN FOX JUMPS OVER THE LAZY DOG
p / .text 12px 1.5

Body copy. The default text color is #1A1A1A. Lines are dense and tight to fit grid-heavy clinical UI.

label 12px 1.0
th .70rem TABLE HEADER CELL
td .75rem Table body cell content
.alert 12px 1.3 Alert message text — see §10 Alerts for the full pattern.
.btn 12px / 500 PRIMARY ACTION

05 Spacing & Sizing

Standardized heights and dimensions. The app is built on these — never invent custom heights without reason.

Core dimensions
What it isValue
Top masthead height50px
Tabs row height43px
Nav item height38px
Header row height (table / list)32px
Toolbar height32px
.form-control input height32px
Native input / textarea height28px
Body row height (table / list)22px
Button — small (default)24px
Button — medium32px
Button — large40px
Sidebar width220px
Border radius (universal)4px
Scrollbar width10px
Gridster handle width6px
Form spacing
PatternValueNotes
.form-groupmargin-bottom: 0.5rem8px between stacked fields
.form-rowmargin: 0 0 10px 0flex row, label + control
.dialog-contentpadding: 20pxflex column, font 14px
.dialog-buttonspadding: 10pxright-aligned, 1px top border
Form group captionpadding: 10px, bg: #e8f1f5DevExtreme dx-form-group-caption
Modal sizes — set via NgbModalOptions.windowClass when opening
ClassMax widthHeightWhen to use
.modal-full-heightanyfull minus 56pxMost common — tall dialogs (SCE, specifications, audit)
.modal-lg800pxautolarger forms
.modal-md600pxautodefault — typical edit/confirmation dialogs
.modal-xl(xl)full minus 80pxrare — full-screen-ish
.modal-lg2800pxfull minus 80pxrare — tall larger forms
.modal-sm400pxautorare — small confirmations

06 Shadows

Listed in production-usage order. Two shadows cover ~95% of the app: --shadow-normal on every card, --shadow-large on every overlay/popover/toast.

Card / tile shadow #1 most used (17+ components)
0 1px 2px rgba(0,0,0,.2)
Overlay / popover lift #2 — toasts, popups, dropdowns, sticky headers
0 3px 15px rgba(0,0,0,.4)
Modal Applied automatically to .modal-content
0 20px 40px rgba(0,0,0,.4)
Dropdown (rare) dx-select-box, mention-list only
0 7px 12px 1px rgba(0,0,0,.4)
Top-normal (rare) Bottom-anchored bars
0 -1px 2px rgba(0,0,0,.2)

07 Z-Index Scale

LayerZ-Index
.dx-popup, .dx-overlay-modal3000
[aria-label][data-balloon-pos]3000
.gridster-item-resizable-handler6000
ngb-modal-backdrop8996
ngb-modal-window8997
.dxc-tooltip9000
.dx-popover-wrapper9002
.dx-overlay-wrapper (dropdowns)9003
.popover9004
::ng-deep .ui-toast (PrimeNG)9006
::ng-deep .dx-invalid-message-content9008
.ui-overlaypanel, dx datebox / dropdown overlay100001
.tooltip100002
Never invent ad-hoc z-index numbers — pick from this scale or coordinate via base/z-index.scss.

08 Buttons

The default .btn is the Narrow button (24px, 12px text, weight 500). Variants are listed in production-usage order — the most common ones are first.

1. Icon-only — most-used button in the product
.btn-icon toolbars, grid actions, dialogs, anywhere space is tight
On dark surfaces — .btn-icon-for-dark
2. Link — inline action that reads like a link
.btn-link open profile, edit row, view details
3. Secondary / Ghost — alternative or cancel action
.btn-secondary (alias .btn-ghost) default · hover · active · focus · disabled
4. Primary — main action on a form / dialog footer
.btn-primary default · hover · active · focus · disabled
Specialized variants — use only when needed
.btn-danger (rare) · .btn-outline-secondary · .btn-outline · round
Sizes
.btn-sm (default, 24px) · .btn-md (32px) · .btn-lg (40px)
Icon weights — light by default, solid for active
Default = fal (Light) · Active / toggled = fas (Solid) production uses 39+ files of fal vs 12 of fas
filter — off / on
star — unfavorited / favorited
bell — off / on
bookmark — off / on
heart — off / liked
visibility — off / on
Rule: use fal fa-{name} (light) for almost every icon — toolbar buttons, badge icons, dialog close buttons, disclosure chevrons. Switch to fas fa-{name} (solid) only when the icon represents a toggled-on / active state — filter is applied, item is favorited, notifications are enabled.

Solid icons render in primary blue (#1F68A8) by default — that's the standard "engaged" cue. The visual shift "thin gray → fat blue" reads as "off → on". Don't override with semantic colors (no yellow on a favorited star, no red on a liked heart) — the blue treatment handles every toggle state. Exceptions: inside .btn-primary / .btn-danger / .badge the solid icon inherits the container's text color; on dark surfaces it goes near-white.

09 Form Elements

Inputs default to 28px tall with a 1px solid #DDDDDD border and 4px radius. On focus the border becomes #1F68A8. Validation errors use a #CD482D border.

Inputs · default · focus · disabled · readonly · error
Focused state — border becomes #1F68A8
Border turns #CD482D. The error message itself goes in an alert at the form level (see §11).

10 Alerts

Inline alerts — Bootstrap-style .alert blocks dropped as a <div> inside dialogs, panels, or forms to surface persistent in-context messages (connection-lost banners, contextual tips, advisories). Not for form validation — validation summaries surface in popup toasts (§16), and empty required fields use red border + placeholder="Required" with no popup. The deprecated .inline-error / .inline-warning text-below-input pattern is gone.

Variants — pick one of these by intent
Common modifier classes
Common modifiers: .mb-0 removes the default 16px bottom margin (use when stacking alerts tightly or as the last element). .rounded-0 removes the radius (use for full-width banner alerts inside dialog headers).
Form validation — three paths (most are NOT inline alerts)
Path A — Empty required field: red border + placeholder="Required". No popup, no inline alert.
Empty required fields are signaled visually only — the red #CD482D border plus the placeholder text "Required" together carry the message. Don't add a popup toast or an inline alert on top of this — it would be over-signaling. The placeholder swap is critical: a never-touched field with only a red border doesn't communicate enough.
Path B — Server-returned (API round-trip) errors: duplicate names, conflicts, permission denials, save failures — anything the API response carries an error for. (Optional) red border on the related input + popup toast with the server's message. See §16.
Trigger from the API call's error handler: this.alerts.showErrorToast(response.error.message) for a single server message, or this.alerts.showModelStateError(response.error.modelState) for a multi-error ModelState response (joins messages with <br/> into one sticky toast). Never render server-returned errors as an inline .alert.alert-danger at the top of the form — the toast is the canonical surface for anything that came back from the server.
Path C — Persistent in-context advisory (connection lost, blocking system state): this IS an inline alert
Inline alerts (§10) live here — for messages that are part of the page state and stay until the underlying condition changes. Not for one-shot validation feedback.

11 Badges

Pill-shaped (10px radius, 22px min-width, 12px text). Listed in production-usage order — success/warning/danger/info/secondary cover almost every badge in the product.

1. Status badges — most-used (pick one of these by default)
Success Warning Danger Info Secondary
2. Outline variants — for dense grids/lists
Softer visual weight when many badges appear together
Success Warning Danger Info Secondary Primary Unassigned (dashed)
With leading icon
Font Awesome icon at the start gets 5px right margin automatically
Complete In Review Failed Info Pending Done Rejected Caution
Counts & transparent
12 3 99+

12 Tables

Header row 32px tall, body row 22px. Header text 11px, body text 12px. Borders are 1px solid #DDDDDD all around.

Default .table
Subject IDSiteVisitStatusUpdated
SUB-0001Site 12ScreeningComplete2026-04-21
SUB-0002Site 03Visit 4In Review2026-04-22
SUB-0003Site 12BaselineQuery2026-04-22
SUB-0004Site 07EOTPending2026-04-23
SUB-0005Site 03Follow-upComplete2026-04-24
Row hover
KRIRiskScoreTrend
Adverse event reporting rateLow0.12
Protocol deviation densityMedium0.43
Query open ageHigh0.81
Site enrollment varianceMedium0.55
Data entry latencyLow0.18
All `.table` rows highlight on hover with #C8E8FA (data-blue-200). Hover any row above to preview. Tables do not alternate row colors — every body row sits on white.

13 Cards & Section Headers

Section header bars
SECTION HEADER (.section-header)
Section content goes here.

Light blue section header (.light-blue-section-header)

Section content goes here.
Secondary header (.secondary-header)
Section content goes here.
Card mixins
@mixin card

Gray-100 fill, gray-300 border, 4px radius. Used for grouping content.

@mixin rounded-borders

10px padding, 1px solid gray-200, 100% height. The default content wrapper.

Open queries 42
Sites 17

14 Toolbars

Listed in production-usage order. The minimal (transparent) toolbar is by far the most-used — that's the one you reach for in panel headers, widget headers, and inset toolbars. The dark gradient toolbar is rare and reserved for the very top of the page.

1. Minimal toolbar — most-used
.minimal-toolbar transparent, used in 30+ files for panels, widgets, inset toolbars
Listing details
Use <toolbar-widget class="minimal-toolbar"> in production. The hand-rolled HTML above is the underlying CSS contract.
2. Secondary toolbar — rare (5 files)
.secondary-toolbar light gray (#F6F6F6), inset filter bars only
Filter results
3. Default (dark gradient) — top-of-page only
.toolbar dark blue gradient — never inside a modal; reserved for the page-level toolbar
Data Central · Subjects

15 Masthead

The 50px top app bar — a dedicated component (<ecs-masthead>) with masthead-only chrome elements that must not be substituted for their page-body equivalents (.dropdown-menu, .nav-tabs, gray .btn-icon, etc.). Background #182B3B, secondary text #CADDEE, hover bg #1E4060, divider lines #215887, active rail #F77623, active filter accent #4EE5FB (masthead only).

15.1 Composite — full masthead with all regions
All seven regions left → right: app grid · brand mark · header label · dropdowns · sub-nav tabs · trailing toolbar (search/filter slots elided)
Data Central Subjects
Hover any element to see its interaction state. The aqua filter icon (#4EE5FB) signals an active filter — this color is masthead-only and must not appear elsewhere.
15.2 App grid & brand mark — leftmost slot
.ecs-menu-btn opens the 850px mega-menu flyout · .eclinical-logo renders the brand mark at 28px tall
15.3 Header label & badges — .ecs-header
16px bold #CADDEE · inline fal fa-chevron-right at 10px for path separators · trailing .toolbar-badge for counts
Data Central Subjects
3 !
15.4 Masthead navigation dropdown — .ecs-dropdown
Fills 50px height · 14px lighter weight · #CADDEE text · right border #215887 · hover bg #1E4060. NOT the same as .dropdown-menu in §18.
Resting · hover · resting (left to right). Cluster lives in .ecs-masthead-navigation-dropdowns-container with border-left: 1px solid #215887 and margin-left: 15px when next to the header label. Popover panel (not rendered inline here) is a fixed 300px wide DevExtreme dx-popover with a dx-list of 34px rows; selected row gets a 3px #F77623 left bar.
15.5 Sub-nav tabs (horizontal) — .sub-nav-container-horizontal
49px tall · white text · 3px #F77623 bottom rail on active item · hover bg #1E4060. NOT the same as .nav-tabs in §17.
Difference vs. .nav-tabs (§17): nav-tabs are 43px with a 2px rail on a light surface; masthead sub-nav is 49px with a 3px rail on the dark #182B3B bar.
15.6 Filter pills — .filter-pill (dark + light variants)
Dark variant (.filter-pill-dark) — only inside .ecs-masthead-filters-container
Light variant (.filter-pill-light) — for filter bars on white/light page bodies, not inside the masthead
Both variants share the same shape: 36px tall, two-button (label + ×), 4px radius, line-1 11px / line-2 12px. Only the colors and border swap. Pills inside .ecs-masthead-filters-container auto-promote to dark.
15.7 Filter pill +N overflow — .ecs-pill-overflow-dropdown
Tail of the pill row — 56px button with +N label and chevron, behind a 1px #215887 left divider
When the row of pills exceeds the available width, the trailing pills are moved into an overflow popover. Algorithm: spill at ≥ 25% of a pill's width past containerRight − 66px.
15.8 Search & search-by — two patterns

The masthead supports two search patterns — pick by intent. Both are content-projection slots ([search] / [searchBy]) so the markup is supplied per-route.

Pattern A — Search-only (no field picker) · use when the search context is unambiguous (single field, single domain)
Standalone .ecs-masthead-search — single input with magnifier icon on the right (#CADDEE, 12px). Width 240px, height 30px, dark bg #1E4060, white text, 4px radius.
Pattern B — Search-by picker + search · use when the user needs to pick which fields to search across (multi-select)
Picker trigger (.ecs-masthead-search-by-btn) — height 30px, min-width 180px, dark #182B3B bg, 1px #215887 border, white text, joined to the search input on the right (radius 4px 0 0 4px). The trailing chevron-down is 10px white. Label is the comma-separated list of selected fields ("Name, Description").

Joined search input picks up radius 0 4px 4px 0 so the two read as one combined widget.

Popover (.ecs-masthead-search-by-popover) — white bg, 1px #DDDDDD border, 4px radius, overlay shadow. Each row (.search-by-option) is a <label> + <input type="checkbox">, 12px text, 6px 14px padding, hover bg #F0F5FA. Checkbox accent uses action blue #1F68A8.
15.9 Trailing toolbar — .ecs-masthead-toolbar
Right-aligned action area · use .btn-icon.btn-icon-for-dark · active filter icon goes #4EE5FB (masthead-only)
15.10 Toolbar badges — .toolbar-badge
Count chips that hang off masthead actions or dropdowns · z-index: 9000 · 4px left margin between
Notifications
3 ! 12
Use the matching badge variant (.badge-warning, .badge-danger, .badge-info) plus .toolbar-badge. For clickable badges, add .toolbar-badge-clickable to get the pointer cursor.
15.11 Masthead-only color tokens (don't use elsewhere)
#182B3B
$blue-900masthead bg, mega-menu footer
#1E4060
$blue-800hover bg, dark filter pill bg
#215887
$blue-700inner divider lines
#1F68A8
$blue-600filter pill active bg
#82B0D9
$blue-400dark filter pill border
#CADDEE
$blue-200secondary text, dropdown selected
#A3C5E2
$blue-300masthead suffix text
#4EE5FB
$aqua-400 (masthead only)active filter icon
#F77623
$active-item-border-colorsub-nav rail (3px), dropdown selected (3px)
#BBBBBB
$gray-400mega-menu dividers
These tokens appear only in the masthead. Don't introduce them in buttons, badges, body text, or page chrome — UI tokens stay in §1 (elluminate Palette).
15.12 Don't confuse masthead chrome with page-body chrome
In a Figma design, if you see…Use
Dropdown trigger inside the dark 50px bar.ecs-dropdown + .ecs-dropdown-button — fills 50px, 14px lighter, #CADDEE
Dropdown menu in a page body.dropdown-menu + .dropdown-item (§18)
Tabs inside the dark 50px bar.sub-nav-container-horizontal — 49px, white, 3px #F77623 rail
Tabs inside a light page body.nav-tabs — 43px, light, 2px #F77623 rail (§17)
Filter pill in the masthead.filter-pill-dark (auto-applied inside .ecs-masthead-filters-container)
Filter pill on a white page.filter-pill-light
Icon button on the dark masthead.btn .btn-icon .btn-icon-for-dark
Icon button on a light page.btn .btn-icon (default — gray)
Active filter icon (any color)#4EE5FB aqua — masthead only
Manual +5 overflow chipUse .ecs-pill-overflow-dropdown — handles measure-and-move
Side drawer for app navigationUse the 850px mega-menu flyout (<ecs-menu>)
See design.md §6.16 for full token tables, §F for the Figma-element map, and §G for the complete anti-pattern checklist.

16 Popup Toasts

Transient floating alerts — primarily for server-returned messages (API round-trip). Use cases:

  • ★ API round-trip validation errors (the canonical use case) — duplicate names, server-enforced uniqueness, permission denials, conflict errors (HTTP 409), save failures, anything in an API response's error payload. Always a toast, never an inline alert.
  • API round-trip success / info — save confirmed, export ready, deletion completed, file uploaded.
  • Async events not initiated by the user — signalr push, websocket event, background job complete, server-pushed notification.
  • Multi-error model stateshowModelStateError(response.error.modelState) joins all server messages with <br/> into one sticky toast.

Rendered by DevExtreme's dx-toast via the shared AlertsService — never hand-rolled. Position: top-center, 20px from top. Width: 370px. Z-index: 9006. Default display time: 5000ms (error toasts are sticky — they stay until dismissed).

Required-field exception: an empty required field is not announced via toast — and usually never reaches the server (the round-trip is short-circuited client-side). Red border + placeholder="Required" only. See §10 path A.

Four variants — each surfaces a different kind of API response
showSuccessToast() · showToast() (info) · showWarningToast() · showErrorToast() (sticky — for server errors)
Every example above is a server-returned message relayed to the user. Toasts share the same shell: 370px × auto, 15px padding, 4px radius, overlay shadow (0 3px 15px rgba(0,0,0,0.4)), and a subtle gray-gradient background (linear-gradient(150deg, #D0D0D0 0%, #FFFFFF 50%, #D6D6D6 75%)) that reads as a "floating glass" surface. The only difference between variants is the icon color (#1F8915 success · #1F68A8 info · #EC7614 warning · #CD482D error).
Usage from Angular — wire toasts into your API callbacks
constructor(private alerts: AlertsService) {}

// Typical API round-trip — toast on both branches:
this.listingApi.save(payload).subscribe({
    next: ()         => this.alerts.showSuccessToast('Saved. Listing applied to all 17 sites.'),
    error: response  => {
        // Single server-returned message (e.g. duplicate name, permission denied):
        this.alerts.showErrorToast(response.error.message);

        // OR — multi-error ModelState from a .NET API response
        // (joined with <br/> into one sticky toast):
        this.alerts.showModelStateError(response.error.modelState);

        // Optionally highlight the offending field in the form:
        if (response.error.field === 'name') this.nameClasses.error = true;
    }
});

// Other server-pushed events:
this.alerts.showToast('Export ready. File is in the downloads panel.');   // info
this.alerts.showWarningToast('Partially saved — 2 sites rejected the update.');
Always use AlertsService from shared/alerts/alerts.service.ts — never call DevExtreme's notify() directly. The service applies the right defaults (5000ms display, top center, error = sticky, close-on-outside-click, close-on-click). Toasts always carry the server's message verbatim — the client is just relaying the API response, not authoring its own copy.
Decision matrix — by where the message originates
Use a popup toast (§16) when…Use an inline alert (§10) when…Use NO popup when…
The message came back from the server — API response (success / error / warning), duplicate name, conflict, permission denied, save failed, model-state payload. Also signalr / websocket / job-complete pushes. The message is a persistent state the client knows locally — connection-lost banners, contextual tips, system-state advisories that hold until they don't. An empty required field is the only issue (and the round-trip was usually short-circuited before the server was even called)
The text is the server's message, relayed verbatim The text is something the client knows independent of any API call The visual (.error border + placeholder="Required") is sufficient on its own
It's transient — disappears after 5 s (errors stay until dismissed) It's persistent — stays until the underlying state changes The signal is in the field itself
Examples: "A listing named 'Subjects' already exists.", "You don't have permission to publish.", "Save failed — conflict on row 47.", "Saved.", "Export ready.", "Job complete." Examples: "Connection lost — reconnect to continue.", "Auto-sync paused.", "Tip: listings inherit permissions from the parent folder." Empty required: "Listing name" / "Visibility" left blank on submit → red border + "Required" placeholder, nothing else.
Rules of thumb: (1) message originated from the server → toast. (2) message is a persistent client-known state → inline alert. (3) required field empty → border + "Required" placeholder, nothing else.

17 Tabs

Active tab uses an orange (#F77623) bottom rail and #F7F7F7 background.

19 Modals

Use <dialog-container> for new dialogs — that component is wrapped around an <ngb-modal> and standardizes the header / body / footer regions. It's the dominant modal pattern in the product (100+ files). The previews below show the rendered shape; in code you write <dialog-container [title]="…" [hideButtonText]="Cancel" [closeButtonText]="Save" [closeButtonClass]="btn-primary">…</dialog-container>. Backdrop is rgba(0,0,0,.4); modal shadow is 0 20px 40px rgba(0,0,0,.4).

Confirmation dialog (using .modal-sm — 400px wide in production)
Header is white with a 1px solid #E8E8E8 bottom border — not the dark page-toolbar gradient.
Form dialog (using .modal-md — 600px wide in production)
All modal sizes — pick by intent
Set via NgbModalOptions.windowClass when opening — never as a static HTML class. Listed in production-usage order (most-used first).
Class Max width Height When to use
.modal-full-height ★ most-used (any width) full minus 56px Tall dialogs — SCE files, specifications, audit log, deliverable assignments. The default reach for any list-heavy or multi-section dialog.
.modal-lg 800px auto Larger forms — recent-exports, importer domains, anything wider than a typical edit form but not full-height.
.modal-md (default) 600px auto The default — typical edit / confirmation dialogs that don't set a windowClass. Note: elluminate's .modal-md is 600px, not Bootstrap's 500px.
.modal-xl (xl width — viewport-bound) full minus 80px Rare — full-screen-ish dialogs (multi-pane editors, comparison views).
.modal-lg2 800px full minus 80px Rare — tall larger forms (combines lg width with full-height-style sizing).
.modal-sm 400px auto Rare — small confirmation dialogs ("Delete this listing?", "Discard changes?"). Note: elluminate's .modal-sm is 400px, not Bootstrap's 300px.
All sizes share the same chrome: white 32px header with 1px solid #E8E8E8 bottom border (never the dark page-toolbar gradient), 20px body padding, 10px right-aligned footer with a 1px solid #EAEAEA top border, 4px radius, rgba(0,0,0,0.4) backdrop, 0 20px 40px rgba(0,0,0,0.4) shadow.
Opening a modal with a size (Angular)
// Tall list-heavy dialog (most common)
this.modalService.open(MyDialogComponent, {
    windowClass: 'modal-full-height',
    backdrop: 'static'
});

// Typical edit / confirmation dialog (default — 600px)
this.modalService.open(MyDialogComponent, {
    windowClass: 'modal-md'
    // or omit windowClass entirely — .modal-md is the default
});

// Small confirmation ("Delete this listing?")
this.modalService.open(ConfirmDialogComponent, {
    windowClass: 'modal-sm'
});
The windowClass is set on the NgbModalOptions at open time, not as a static class on the modal markup. backdrop: 'static' prevents click-outside dismissal — use for any dialog with unsaved work.

20 Tooltips

Use ng-bootstrap's [ngbTooltip] directive for almost every tooltip in the product (used in 100+ components — toolbars, icon buttons, table cells, badges, form fields). It renders a .tooltip element styled with elluminate's overrides: 12px white text on near-black, 350px max-width.

Visual reference (the .tooltip element rendered by ngbTooltip)
Saves and closes the dialog.
In Angular code: <button [ngbTooltip]="'Saves and closes the dialog.'">…</button>. Position via placement="top" (default) / "bottom" / "left" / "right".

21 Accordion

Header 32px tall on #F6F6F6, body has 0 0 6px 0 padding and 60px minimum height. Disclosure indicator is a chevron, never plus/minus. Click to expand.

Study details
Study ELL-2026-001 — Phase IIIb. Enrollment open across 17 sites in 4 countries.
Risk profile
KRI panel: 3 medium, 1 high. Last refreshed 4 hours ago.
Configuration
Active review plan: RP-CDISC-Standard-v3. EIQ Orchestrator rules: 12 active, 3 disabled.

22 Risk Levels

Use .risk-level-{undefined|low|high-low|low-medium|high-medium|high|extreme-high} — never invent new levels.

Undefined
Low
High-Low
Low-Medium
High-Medium
High
Extreme-High

23 Indicators

"Thinking" indicator from the Matilda assistant: animated text gradient + breathing dot.

Matilda is thinking…
Gradient sweep across #767676 → #1A1A1A → #767676, 1s linear infinite. Dot is #1F68A8, 2.5s breathe.
Active rail indicator
List item one
Active list item (rail color #F77623)
List item three
List item four