Blau — Design System
All design tokens, components, and patterns used in Saúl Ossorio's portfolio. Every component is rendered with the actual CSS from style.css — no mocks. Click motion demos to replay them.
Foundation
Core design tokens defined in :root in style.css. Never hardcode a hex value — always reference a token. Changing a token updates every component that uses it.
Color tokens
#EF5958 — used only for the dot rage easter egg. Not a persistent token.
Font families
Raleway
Aa Bb Cc — weights 400 600 700 800
Open Sans
Aa Bb Cc — weights 300 400 600 700 + italic
Layout tokens
Type Scale
Two typefaces, contextual sizing. Each row is rendered at its real size — the visual weight difference between levels is what matters. Sizes shown are desktop target values; fluid headings use clamp(min, viewport, max) in CSS so they scale smoothly across screen sizes.
Atomic Design
The portfolio follows atomic design thinking. Design tokens feed atoms, atoms compose into molecules, molecules form organisms, organisms assemble into the page template, and the template filled with real content is the final page.
Each organism has its own semantic landmark, ARIA roles, scroll/fade behavior, and GTM data attributes. Built inside renderPage() in index.html.
.layout — fixed sidebar (var(--sw) = 230px) + fluid main. Main centers children at max-width 1200px with horizontal padding.
Content from data.js is injected at runtime by renderPage(). Language switching rerenders all organisms instantly — same template, new content, no page reload.
Brand
The blue dot is the sole brand mark. No ring, circle, or frame — just the dot. It appears in two size contexts, each with different behavior.
Interactive Elements
Pills/CTAs and the accordion. All states are live — click to interact.
Product Designer & UX Consultant
Fexpocruz · Contract · Bolivia
Led UX and digital product design for Expocruz 2025.
Master's Degree, Design
Universidade Federal do Paraná (UFPR)
Dissertation: Usability Heuristics for Immersive Virtual Learning Environments.
Bachelor's Degree, Science and Technology
Universidade Federal de Santa Catarina (UFSC)
Lists
Two patterns sharing the same two-column grid: 155px label column + 1fr content.
Web Analytics Consultant
Fexpocruz · Contract · Remote
Drove 70% increase in traffic and 350% increase in online ticket sales.
Native or bilingual proficiency
Celpe-Bras
Design & UX
Product Design · UX Research · UI Design · Wireframing · Prototyping · Figma · Webflow · Accessibility
Data & Analytics
Google Analytics 4 · GTM · BigQuery · SQL · Python · Data Visualization · Microsoft Clarity
Layout
Structural elements shared across all sections.
— section above —
— section below —
Triggered by IntersectionObserver on scroll into viewport
Motion
Click each card to replay the animation. All animations respect prefers-reduced-motion: reduce — durations collapse to 0.01ms for users who opt out.
fadeUp / .fade.in
opacity 0→1 · translateY 24px→0 · 0.65s ease · IntersectionObserver threshold 0.08
dotPop
scale 0→1.08→1 · 0.9s cubic-bezier(.22,.61,.36,1) · hero dot entrance on load
scrollDot
translateY 0→14px + opacity 1→0 · 1.6s ease infinite · running live above
growLine
width 0→100% + opacity · 2.5s cubic-bezier(.05,0,.15,1) · contact section divider
Dot bounce (on click)
scale 1→0.82→1.06→1 · 380ms · Web Animations API (GPU composited)
Content revealed with max-height transition.
Accordion open/close
max-height 0→9999px · 0.45s ease · arrow rotates 90° · click trigger above
Mobile name reveal
opacity 0→1 + translateY 8px→0 · 0.4s ease · triggers when hero H1 leaves viewport
Burger menu open/close
lines 1+3 rotate ±45° · line 2 width→0 · 0.35s cubic-bezier · click to toggle
Accessibility
WCAG AA compliance patterns implemented throughout the portfolio. Contrast ratios are tested against white (#ffffff).
Skip to main content
First focusable element in the DOM. Visually hidden until focused — then appears at the top of the page. Targets #main-content with tabindex="-1".
Keyboard focus indicator
:focus-visible — 2px solid --blue, 3px offset, border-radius 4px. Hidden for mouse via :focus:not(:focus-visible) so it only shows for keyboard users.
ARIA attributes
aria-expanded on accordion triggers and burger. aria-modal + role="dialog" on image lightbox. aria-hidden="true" on decorative dots, dividers, and all SVGs.
Keyboard navigation
Image modal: ← → navigate carousel, Esc closes. Nav links use tabindex="0" + onkeydown Enter handler since they're role="button" anchors.
prefers-reduced-motion
Global rule sets all durations to 0.01ms and disables smooth scroll. Exception: scrollDot re-enabled on mobile via !important — a simple translate/opacity dot is not a vestibular risk.
Color contrast ratios
--text #1a1a1a → 16.1:1 AAA ·
--mid #555 → 7.46:1 AAA ·
--blue #0071C5 → 4.56:1 AA ·
--light #999 → 2.85:1 — decorative/secondary labels only, never body copy.
Alt text
Profile: "Portrait of Saúl Ossorio". Project thumbnails use the project title. Carousel slides use the alt defined per-image in data.js → images[].alt.
Inline SVG accessibility
All SVGs carry aria-hidden="true" and focusable="false". The accessible name is provided by the parent <a> via aria-label="Visit LinkedIn (opens in new tab)".
Language declaration
lang on <html> updates on every language switch via document.documentElement.lang = lang. Screen readers use this to select the correct pronunciation engine.
Landmark roles
Uses <aside>, <main>, <header>, <footer>, <nav>, <article>, <section> with aria-labelledby pointing to each section heading.
Social
Two variants: icon + label for hero and contact sections, icon-only for sidebar and footer. All three states shown for each.
Social tag — icon + label
border-radius 100px · --tag-bg fill · 0.78rem · opacity .75 default → 1 on hover · bg darkens + border darkens + text to --text on hover
Social icon — icon only
15×15px SVG · --light default → --blue hover · transition color .2s · sidebar only