Technical Implementation Review
Score: 8.5/10 Potential: 9/10 Gap: 0.5 points
Executive Summary
Your technical implementation is significantly above average for a portfolio site. Clean code organization, proper semantic HTML, good accessibility practices, and thoughtful architecture. However, there are maintainability issues that will create problems as the site scales: inline JavaScript, duplicated navigation logic, and imperative DOM manipulation.
Bottom line: You write good code. Now write maintainable code.
What You’re Doing Right
1. Code Organization (9/10)
Directory structure is clean and follows Jekyll conventions:
_sass/
├── _variables.scss (83 lines) - Design tokens
├── _base.scss (84 lines) - Resets and base styles
├── _typography.scss (143 lines) - Font styles
├── _layout.scss (605 lines) - Page layouts
├── _components.scss (489 lines) - Reusable components
├── _utilities.scss (123 lines) - Helper classes
├── _responsive.scss (363 lines) - Media queries
├── _gallery.scss (585 lines) - Gallery components
├── main.scss (11 lines) - Imports all above
└── design-system-pro.scss (726 lines) - Alternative system
Total: 3,211 lines across 10 files
Good decisions:
- ✅ No monolithic files (largest is 726 lines)
- ✅ Clear separation of concerns
- ✅ Consistent naming conventions
- ✅ Proper SCSS nesting and variables
Note: You have two design systems (main.scss imports vs design-system-pro.scss). This is technical debt—decide on one.
2. Semantic HTML (9/10)
From _layouts/default.html:
<!-- Line 33: Accessibility -->
<a href="#main" class="sr-only">Skip to main content</a>
<!-- Lines 36-93: Semantic structure -->
<header class="site-header" id="site-header">
<nav class="site-nav" aria-label="Primary navigation">
<!-- Navigation -->
</nav>
</header>
<main id="main">
<article class="page">
<div class="container container-narrow">
<header class="page-header">
<h1 class="page-title">Design & UX Review</h1>
</header>
<div class="page-content">
<h1 id="design--ux-review">Design & UX Review</h1>
<p><strong>Score</strong>: 7/10
<strong>Potential</strong>: 8/10
<strong>Gap</strong>: 1 point</p>
<h2 id="executive-summary">Executive Summary</h2>
<p>Your design system is technically competent with good fundamentals (typography scale, consistent spacing, semantic colors). However, the aesthetic choices are <strong>safe to the point of invisibility</strong>. The site follows generic portfolio patterns without visual personality or memorable moments. Technical execution is solid; creative expression is missing.</p>
<h2 id="the-core-problem-template-thinking">The Core Problem: Template Thinking</h2>
<h3 id="what-makes-design-generic">What Makes Design “Generic”</h3>
<p><strong>Not about quality</strong> - Your code is clean, your spacing is consistent, your colors are accessible.</p>
<p><strong>It’s about differentiation</strong> - When I see your site, I could swap the content with 50 other portfolios and the design would still work. That’s the problem.</p>
<h3 id="evidence-of-template-patterns">Evidence of Template Patterns</h3>
<h4 id="pattern-1-the-standard-hero">Pattern 1: The Standard Hero</h4>
<p><strong>From <code class="language-plaintext highlighter-rouge">index.html</code> (lines 7-34):</strong></p>
<div class="language-html highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt"><section</span> <span class="na">class=</span><span class="s">"hero"</span><span class="nt">></span>
<span class="nt"><div</span> <span class="na">class=</span><span class="s">"container container-narrow"</span><span class="nt">></span>
<span class="nt"><div</span> <span class="na">class=</span><span class="s">"hero-content"</span><span class="nt">></span>
<span class="nt"><div</span> <span class="na">class=</span><span class="s">"hero-avatar"</span><span class="nt">></span>
<span class="nt"><img</span> <span class="na">src=</span><span class="s">"/assets/images/headshot.jpg"</span> <span class="na">alt=</span><span class="s">"..."</span><span class="nt">></span>
<span class="nt"></div></span>
<span class="nt"><h1</span> <span class="na">class=</span><span class="s">"hero-title"</span><span class="nt">></span>Brandon JP Lambert<span class="nt"></h1></span>
<span class="nt"><p</span> <span class="na">class=</span><span class="s">"hero-tagline"</span><span class="nt">></span>Language Learning <span class="err">&</span> Teaching<span class="nt"></p></span>
<span class="nt"><div</span> <span class="na">class=</span><span class="s">"hero-actions"</span><span class="nt">></span>
<span class="nt"><a</span> <span class="na">href=</span><span class="s">"/work/"</span> <span class="na">class=</span><span class="s">"btn btn-primary"</span><span class="nt">></span>Learn More<span class="nt"></a></span>
<span class="nt"><a</span> <span class="na">href=</span><span class="s">"/contact/"</span> <span class="na">class=</span><span class="s">"btn btn-secondary"</span><span class="nt">></span>Contact Me<span class="nt"></a></span>
<span class="nt"></div></span>
<span class="nt"></div></span>
<span class="nt"></div></span>
<span class="nt"></section></span>
</code></pre></div></div>
<p><strong>This is Every Portfolio Ever:</strong></p>
<ol>
<li>Centered avatar</li>
<li>Name</li>
<li>Tagline</li>
<li>Two buttons</li>
</ol>
<p><strong>No judgment</strong> - it works. But it’s <strong>unmemorable</strong>.</p>
<p><strong>Zero portfolios examined:</strong> Can you name a single portfolio that has this layout and stuck with you?</p>
<h4 id="pattern-2-the-translateย-2px-card-hover">Pattern 2: The Translateย(-2px) Card Hover</h4>
<p><strong>From <code class="language-plaintext highlighter-rouge">_sass/_components.scss</code> (lines 11-14):</strong></p>
<div class="language-scss highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">&</span><span class="nd">:hover</span> <span class="p">{</span>
<span class="nl">transform</span><span class="p">:</span> <span class="nf">translateY</span><span class="p">(</span><span class="m">-2px</span><span class="p">);</span>
<span class="nl">border-color</span><span class="p">:</span> <span class="nf">var</span><span class="p">(</span><span class="o">--</span><span class="n">color-accent</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div></div>
<p><strong>Usage count in the industry:</strong> ~10 million websites</p>
<p><strong>Why it’s overused:</strong> It’s the default Tailwind/Bootstrap hover effect. It works, but signals “I used the standard pattern.”</p>
<p><strong>Not bad</strong> - just <strong>unoriginal</strong>.</p>
<h4 id="pattern-3-the-academic-blue">Pattern 3: The Academic Blue</h4>
<p><strong>From <code class="language-plaintext highlighter-rouge">_sass/_variables.scss</code> (lines 8):</strong></p>
<div class="language-scss highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="na">--color-accent</span><span class="p">:</span> <span class="mh">#2c5282</span><span class="p">;</span> <span class="c1">// Deep academic blue</span>
</code></pre></div></div>
<p><strong>This color appears on:</strong></p>
<ul>
<li>University websites</li>
<li>LinkedIn</li>
<li>Conservative financial sites</li>
<li>Government portals</li>
<li>Your portfolio</li>
</ul>
<p><strong>It’s safe, professional, and forgettable.</strong></p>
<h3 id="why-safe-is-dangerous">Why “Safe” is Dangerous</h3>
<p><strong>Safe design means:</strong></p>
<ul>
<li>✅ You won’t offend anyone</li>
<li>✅ It’s accessible and professional</li>
<li>❌ No one remembers it</li>
<li>❌ Doesn’t reflect personality</li>
<li>❌ Doesn’t differentiate you</li>
</ul>
<p><strong>In a competitive market, memorable > safe.</strong></p>
<h2 id="design-system-analysis">Design System Analysis</h2>
<h3 id="-whats-working-well">✅ What’s Working Well</h3>
<h4 id="1-typography-scale-_variablesscss-lines-22-30">1. <strong>Typography Scale</strong> (_variables.scss, lines 22-30)</h4>
<div class="language-scss highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="na">--font-size-xs</span><span class="p">:</span> <span class="m">0</span><span class="mi">.64rem</span><span class="p">;</span>
<span class="na">--font-size-sm</span><span class="p">:</span> <span class="m">0</span><span class="mi">.8rem</span><span class="p">;</span>
<span class="na">--font-size-base</span><span class="p">:</span> <span class="m">1rem</span><span class="p">;</span>
<span class="na">--font-size-md</span><span class="p">:</span> <span class="m">1</span><span class="mi">.25rem</span><span class="p">;</span>
<span class="na">--font-size-lg</span><span class="p">:</span> <span class="m">1</span><span class="mi">.563rem</span><span class="p">;</span>
<span class="na">--font-size-xl</span><span class="p">:</span> <span class="m">1</span><span class="mi">.953rem</span><span class="p">;</span>
<span class="na">--font-size-2xl</span><span class="p">:</span> <span class="m">2</span><span class="mi">.441rem</span><span class="p">;</span>
<span class="na">--font-size-3xl</span><span class="p">:</span> <span class="m">3</span><span class="mi">.052rem</span><span class="p">;</span>
</code></pre></div></div>
<p><strong>Good:</strong></p>
<ul>
<li>Proper modular scale (1.25 ratio)</li>
<li>Sufficient range for hierarchy</li>
<li>Semantic naming</li>
</ul>
<p><strong>Observation:</strong> You have 8 sizes but probably only use 4-5 regularly.</p>
<h4 id="2-spacing-system-_variablesscss-lines-43-53">2. <strong>Spacing System</strong> (_variables.scss, lines 43-53)</h4>
<div class="language-scss highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="na">--space-2</span><span class="p">:</span> <span class="m">0</span><span class="mi">.5rem</span><span class="p">;</span> <span class="c1">// 8px</span>
<span class="na">--space-3</span><span class="p">:</span> <span class="m">1rem</span><span class="p">;</span> <span class="c1">// 16px</span>
<span class="na">--space-4</span><span class="p">:</span> <span class="m">1</span><span class="mi">.5rem</span><span class="p">;</span> <span class="c1">// 24px</span>
<span class="na">--space-5</span><span class="p">:</span> <span class="m">2rem</span><span class="p">;</span> <span class="c1">// 32px</span>
</code></pre></div></div>
<p><strong>Good:</strong></p>
<ul>
<li>Based on 8px grid (industry standard)</li>
<li>Consistent mathematical relationship</li>
<li>Prevents arbitrary spacing values</li>
</ul>
<p><strong>Observation:</strong> This alone puts you ahead of many portfolios.</p>
<h4 id="3-color-naming-_variablesscss-lines-4-12">3. <strong>Color Naming</strong> (_variables.scss, lines 4-12)</h4>
<div class="language-scss highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="na">--color-ink</span><span class="p">:</span> <span class="mh">#1a1a1a</span><span class="p">;</span> <span class="c1">// Primary text</span>
<span class="na">--color-paper</span><span class="p">:</span> <span class="mh">#fafaf9</span><span class="p">;</span> <span class="c1">// Background</span>
<span class="na">--color-accent</span><span class="p">:</span> <span class="mh">#2c5282</span><span class="p">;</span> <span class="c1">// Deep academic blue</span>
<span class="na">--color-secondary</span><span class="p">:</span> <span class="mh">#718096</span><span class="p">;</span> <span class="c1">// Muted gray</span>
</code></pre></div></div>
<p><strong>Good:</strong></p>
<ul>
<li>Semantic, not descriptive (ink/paper vs dark-gray/light-gray)</li>
<li>Clear purpose for each color</li>
<li>Accessible contrast ratios</li>
</ul>
<p><strong>Observation:</strong> Your naming is better than your color choices.</p>
<h4 id="4-font-pairing-_variablesscss-lines-32-35">4. <strong>Font Pairing</strong> (_variables.scss, lines 32-35)</h4>
<div class="language-scss highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="na">--font-body</span><span class="p">:</span> <span class="s1">'Inter'</span><span class="o">,</span> <span class="o">-</span><span class="n">apple-system</span><span class="o">,</span> <span class="n">BlinkMacSystemFont</span><span class="o">,</span> <span class="s1">'Segoe UI'</span><span class="o">...</span>
<span class="o">--</span><span class="n">font-heading</span><span class="o">:</span> <span class="s1">'Crimson Text'</span><span class="o">,</span> <span class="s1">'EB Garamond'</span><span class="o">,</span> <span class="n">Georgia</span><span class="o">,</span> <span class="nb">serif</span><span class="p">;</span>
<span class="na">--font-mono</span><span class="p">:</span> <span class="s1">'JetBrains Mono'</span><span class="o">,</span> <span class="s1">'Fira Code'</span><span class="o">,</span> <span class="nb">monospace</span><span class="p">;</span>
</code></pre></div></div>
<p><strong>Good:</strong></p>
<ul>
<li>Classic pairing: serif headings + sans body</li>
<li>Appropriate fallbacks</li>
<li>Monospace for code (relevant for dev portfolio)</li>
</ul>
<p><strong>Observation:</strong> This pairing appears on 1000+ dev portfolios. It’s the “Helvetica/Georgia” of 2025.</p>
<h3 id="️-what-needs-improvement">⚠️ What Needs Improvement</h3>
<h4 id="1-color-palette-is-too-conservative">1. <strong>Color Palette is Too Conservative</strong></h4>
<p><strong>Current palette:</strong></p>
<ul>
<li>Deep blue (#2c5282)</li>
<li>Muted gray (#718096)</li>
<li>Near-black (#1a1a1a)</li>
<li>Off-white (#fafaf9)</li>
</ul>
<p><strong>This palette says:</strong> “Corporate, safe, don’t take risks”</p>
<p><strong>What it should say:</strong> “Educator who experiments, creates, and thinks differently”</p>
<p><strong>Problems:</strong></p>
<ol>
<li><strong>No warmth</strong> - All cool colors, nothing inviting</li>
<li><strong>No energy</strong> - No vibrant accent for important actions</li>
<li><strong>No personality</strong> - Could be anyone’s site</li>
</ol>
<p><strong>Where are your photography colors?</strong> You mention Letratos as a photography project. Why isn’t your visual palette informed by your photography?</p>
<h4 id="2-layout-is-too-uniform">2. <strong>Layout is Too Uniform</strong></h4>
<p><strong>Evidence:</strong> All project cards are identical (ai-projects.html, lines 34-123)</p>
<div class="language-html highlighter-rouge"><div class="highlight"><pre class="highlight"><code>
<span class="nt"><div</span> <span class="na">class=</span><span class="s">"card project-card"</span> <span class="na">data-category=</span><span class="s">"Educational"</span><span class="nt">></span>
<span class="c"><!-- Same structure for every project --></span>
<span class="nt"></div></span>
<span class="nt"><div</span> <span class="na">class=</span><span class="s">"card project-card"</span> <span class="na">data-category=</span><span class="s">"Educational"</span><span class="nt">></span>
<span class="c"><!-- Same structure for every project --></span>
<span class="nt"></div></span>
<span class="nt"><div</span> <span class="na">class=</span><span class="s">"card project-card"</span> <span class="na">data-category=</span><span class="s">"Portfolio"</span><span class="nt">></span>
<span class="c"><!-- Same structure for every project --></span>
<span class="nt"></div></span>
<span class="nt"><div</span> <span class="na">class=</span><span class="s">"card project-card"</span> <span class="na">data-category=</span><span class="s">"Educational Games"</span><span class="nt">></span>
<span class="c"><!-- Same structure for every project --></span>
<span class="nt"></div></span>
<span class="nt"><div</span> <span class="na">class=</span><span class="s">"card project-card"</span> <span class="na">data-category=</span><span class="s">"Educational Games"</span><span class="nt">></span>
<span class="c"><!-- Same structure for every project --></span>
<span class="nt"></div></span>
<span class="nt"><div</span> <span class="na">class=</span><span class="s">"card project-card"</span> <span class="na">data-category=</span><span class="s">"Educational"</span><span class="nt">></span>
<span class="c"><!-- Same structure for every project --></span>
<span class="nt"></div></span>
<span class="nt"><div</span> <span class="na">class=</span><span class="s">"card project-card"</span> <span class="na">data-category=</span><span class="s">"Data Visualization"</span><span class="nt">></span>
<span class="c"><!-- Same structure for every project --></span>
<span class="nt"></div></span>
<span class="nt"><div</span> <span class="na">class=</span><span class="s">"card project-card"</span> <span class="na">data-category=</span><span class="s">"Educational"</span><span class="nt">></span>
<span class="c"><!-- Same structure for every project --></span>
<span class="nt"></div></span>
<span class="nt"><div</span> <span class="na">class=</span><span class="s">"card project-card"</span> <span class="na">data-category=</span><span class="s">"E-commerce"</span><span class="nt">></span>
<span class="c"><!-- Same structure for every project --></span>
<span class="nt"></div></span>
<span class="nt"><div</span> <span class="na">class=</span><span class="s">"card project-card"</span> <span class="na">data-category=</span><span class="s">"Data Visualization"</span><span class="nt">></span>
<span class="c"><!-- Same structure for every project --></span>
<span class="nt"></div></span>
<span class="nt"><div</span> <span class="na">class=</span><span class="s">"card project-card"</span> <span class="na">data-category=</span><span class="s">"Creative Platform"</span><span class="nt">></span>
<span class="c"><!-- Same structure for every project --></span>
<span class="nt"></div></span>
<span class="nt"><div</span> <span class="na">class=</span><span class="s">"card project-card"</span> <span class="na">data-category=</span><span class="s">"Educational"</span><span class="nt">></span>
<span class="c"><!-- Same structure for every project --></span>
<span class="nt"></div></span>
<span class="nt"><div</span> <span class="na">class=</span><span class="s">"card project-card"</span> <span class="na">data-category=</span><span class="s">"Creative Tools"</span><span class="nt">></span>
<span class="c"><!-- Same structure for every project --></span>
<span class="nt"></div></span>
<span class="nt"><div</span> <span class="na">class=</span><span class="s">"card project-card"</span> <span class="na">data-category=</span><span class="s">"Productivity Tools"</span><span class="nt">></span>
<span class="c"><!-- Same structure for every project --></span>
<span class="nt"></div></span>
<span class="nt"><div</span> <span class="na">class=</span><span class="s">"card project-card"</span> <span class="na">data-category=</span><span class="s">"Educational"</span><span class="nt">></span>
<span class="c"><!-- Same structure for every project --></span>
<span class="nt"></div></span>
<span class="nt"><div</span> <span class="na">class=</span><span class="s">"card project-card"</span> <span class="na">data-category=</span><span class="s">"Educational"</span><span class="nt">></span>
<span class="c"><!-- Same structure for every project --></span>
<span class="nt"></div></span>
<span class="nt"><div</span> <span class="na">class=</span><span class="s">"card project-card"</span> <span class="na">data-category=</span><span class="s">"Educational"</span><span class="nt">></span>
<span class="c"><!-- Same structure for every project --></span>
<span class="nt"></div></span>
<span class="nt"><div</span> <span class="na">class=</span><span class="s">"card project-card"</span> <span class="na">data-category=</span><span class="s">"Educational"</span><span class="nt">></span>
<span class="c"><!-- Same structure for every project --></span>
<span class="nt"></div></span>
</code></pre></div></div>
<p><strong>Every project gets:</strong></p>
<ul>
<li>Same width card</li>
<li>Same height image</li>
<li>Same text layout</li>
<li>Same button arrangement</li>
</ul>
<p><strong>Result:</strong> Visual monotony. Nothing stands out as “most important.”</p>
<p><strong>Better approach:</strong> Differentiate by project status/importance:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>[Featured Project - Full Width]
+------------------------------------------+
| Large Image | Description |
| Gallery | Key Metrics |
| | [Demo] [Code] |
+------------------------------------------+
[Active Projects - 2 Column]
+--------------------+ +--------------------+
| Image | | Image |
| Title | | Title |
| Brief Desc | | Brief Desc |
+--------------------+ +--------------------+
[Prototypes - 3 Column]
+------+ +------+ +------+
| Icon | | Icon | | Icon |
| Name | | Name | | Name |
+------+ +------+ +------+
</code></pre></div></div>
<p>This creates <strong>visual hierarchy</strong> and <strong>guides attention</strong>.</p>
<h4 id="3-no-personality-moments">3. <strong>No Personality Moments</strong></h4>
<p><strong>Personality</strong> = unexpected delighters that make people smile or pause</p>
<p><strong>Current count:</strong> 0</p>
<p><strong>Examples from other portfolios:</strong></p>
<ul>
<li>Custom 404 page with humor</li>
<li>Animated illustrations that react to scroll</li>
<li>Easter eggs (Konami code, hidden messages)</li>
<li>Personal photos/behind-the-scenes</li>
<li>Hand-drawn elements</li>
<li>Playful micro-interactions</li>
<li>Dark mode with personality (not just inverted colors)</li>
</ul>
<p><strong>Your opportunity:</strong> You’re a <strong>photographer</strong> and <strong>language learner</strong>. Where are:</p>
<ul>
<li>Bilingual easter eggs?</li>
<li>Your photos used as backgrounds?</li>
<li>Spanish idioms as section headers?</li>
<li>Teaching artifacts (old lesson plans, student feedback)?</li>
</ul>
<h4 id="4-button-design-is-generic">4. <strong>Button Design is Generic</strong></h4>
<p><strong>From <code class="language-plaintext highlighter-rouge">_sass/_components.scss</code> (lines 33-88):</strong></p>
<div class="language-scss highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nc">.btn</span> <span class="p">{</span>
<span class="nl">display</span><span class="p">:</span> <span class="n">inline-block</span><span class="p">;</span>
<span class="nl">padding</span><span class="p">:</span> <span class="m">0</span><span class="mi">.5rem</span> <span class="m">1</span><span class="mi">.25rem</span><span class="p">;</span>
<span class="nl">border-radius</span><span class="p">:</span> <span class="nf">var</span><span class="p">(</span><span class="o">--</span><span class="n">border-radius-sm</span><span class="p">);</span> <span class="c1">// 2px</span>
<span class="nl">font-size</span><span class="p">:</span> <span class="m">0</span><span class="mi">.875rem</span><span class="p">;</span>
<span class="nl">font-weight</span><span class="p">:</span> <span class="m">500</span><span class="p">;</span>
<span class="c1">// ...</span>
<span class="p">}</span>
</code></pre></div></div>
<p><strong>This button could be on:</strong> Amazon, Shopify, WordPress, Medium, your site</p>
<p><strong>What makes a memorable button?</strong></p>
<ul>
<li>Unique shape/radius</li>
<li>Motion on hover (not just color change)</li>
<li>Sound feedback (subtle)</li>
<li>Contextual variations</li>
</ul>
<p><strong>Example of personality:</strong></p>
<div class="language-scss highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nc">.btn-primary</span> <span class="p">{</span>
<span class="c1">// Current: flat blue rectangle</span>
<span class="c1">// Alternative 1: Subtle skew</span>
<span class="nl">transform</span><span class="p">:</span> <span class="nf">skewX</span><span class="p">(</span><span class="m">-2deg</span><span class="p">);</span>
<span class="c1">// Alternative 2: Bottom border indicator</span>
<span class="nl">border-bottom</span><span class="p">:</span> <span class="m">3px</span> <span class="nb">solid</span> <span class="nf">var</span><span class="p">(</span><span class="o">--</span><span class="n">color-accent-dark</span><span class="p">);</span>
<span class="c1">// Alternative 3: Arrow that slides in</span>
<span class="k">&</span><span class="nd">::after</span> <span class="p">{</span>
<span class="nl">content</span><span class="p">:</span> <span class="s2">"→"</span><span class="p">;</span>
<span class="nl">opacity</span><span class="p">:</span> <span class="m">0</span><span class="p">;</span>
<span class="nl">transform</span><span class="p">:</span> <span class="nf">translateX</span><span class="p">(</span><span class="m">-10px</span><span class="p">);</span>
<span class="nl">transition</span><span class="p">:</span> <span class="n">all</span> <span class="m">0</span><span class="mi">.2s</span><span class="p">;</span>
<span class="p">}</span>
<span class="k">&</span><span class="nd">:hover::after</span> <span class="p">{</span>
<span class="nl">opacity</span><span class="p">:</span> <span class="m">1</span><span class="p">;</span>
<span class="nl">transform</span><span class="p">:</span> <span class="nf">translateX</span><span class="p">(</span><span class="m">5px</span><span class="p">);</span>
<span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>
<p><strong>Not saying use these</strong> - but your buttons have <strong>zero personality</strong>.</p>
<h2 id="missing-visual-elements">Missing Visual Elements</h2>
<h3 id="1-photography-integration">1. <strong>Photography Integration</strong></h3>
<p><strong>You’re a photographer</strong>, yet:</p>
<ul>
<li>No photo gallery on homepage</li>
<li>Letratos project buried in project list</li>
<li>Photography not part of visual identity</li>
<li>No photos used as section backgrounds/headers</li>
</ul>
<p><strong>Opportunity:</strong></p>
<div class="language-html highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"><!-- Hero Section with your photo --></span>
<span class="nt"><section</span> <span class="na">class=</span><span class="s">"hero"</span> <span class="na">style=</span><span class="s">"background-image: url('your-photo.jpg');"</span><span class="nt">></span>
<span class="nt"><div</span> <span class="na">class=</span><span class="s">"hero-overlay"</span><span class="nt">></span>
<span class="c"><!-- Content with readable contrast --></span>
<span class="nt"></div></span>
<span class="nt"></section></span>
<span class="c"><!-- About section with personal photo --></span>
<span class="nt"><section</span> <span class="na">class=</span><span class="s">"about"</span><span class="nt">></span>
<span class="nt"><div</span> <span class="na">class=</span><span class="s">"about-content"</span><span class="nt">></span>
<span class="nt"><img</span> <span class="na">src=</span><span class="s">"you-teaching.jpg"</span> <span class="na">alt=</span><span class="s">"Teaching in Medellín"</span><span class="nt">></span>
<span class="nt"><p></span>This is me in 2020, teaching English in Colombia...<span class="nt"></p></span>
<span class="nt"></div></span>
<span class="nt"></section></span>
</code></pre></div></div>
<p><strong>Why this matters:</strong> It <strong>humanizes</strong> your portfolio and shows <strong>another dimension</strong> of who you are.</p>
<h3 id="2-bilingual-design-elements">2. <strong>Bilingual Design Elements</strong></h3>
<p><strong>You have full Spanish translation</strong>, but design doesn’t reflect bilingualism:</p>
<ul>
<li>No visual language indicator beyond EN/ES buttons</li>
<li>No Spanish typography considerations</li>
<li>No cultural visual references</li>
</ul>
<p><strong>Ideas:</strong></p>
<ul>
<li>Section headers in both languages stacked</li>
<li>Spanish idiom illustrations</li>
<li>Color palette inspired by Colombian culture</li>
<li>Typography that honors Spanish diacritics</li>
</ul>
<h3 id="3-educational-artifacts">3. <strong>Educational Artifacts</strong></h3>
<p><strong>You’re a 4th-generation educator</strong>, yet:</p>
<ul>
<li>No teaching photos</li>
<li>No student work examples (with permission)</li>
<li>No old lesson plans or handouts</li>
<li>No visual timeline of teaching career</li>
</ul>
<p><strong>Opportunity:</strong> Create a “Teaching History” visual timeline:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Great-grandfather (1940s) → Grandfather (1970s) → Father (1990s) → You (2010s)
[Photo] [Photo] [Photo] [Photo]
Teaching: Math Teaching: Science Teaching: History Teaching: Languages
Medium: Chalkboard Medium: Overhead Medium: Computer Medium: AI
</code></pre></div></div>
<p>This is <strong>unique, memorable, and meaningful</strong>.</p>
<h2 id="specific-design-improvements">Specific Design Improvements</h2>
<h3 id="1-homepage-hero---add-asymmetry">1. Homepage Hero - Add Asymmetry</h3>
<p><strong>Current layout (index.html, lines 8-32):</strong> Centered, symmetrical, predictable</p>
<p><strong>Improved layout:</strong></p>
<div class="language-html highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt"><section</span> <span class="na">class=</span><span class="s">"hero hero-asymmetric"</span><span class="nt">></span>
<span class="nt"><div</span> <span class="na">class=</span><span class="s">"hero-left"</span><span class="nt">></span>
<span class="c"><!-- Large personal photo from Colombia --></span>
<span class="nt"><img</span> <span class="na">src=</span><span class="s">"brandon-teaching.jpg"</span> <span class="na">alt=</span><span class="s">"Teaching"</span><span class="nt">></span>
<span class="nt"></div></span>
<span class="nt"><div</span> <span class="na">class=</span><span class="s">"hero-right"</span><span class="nt">></span>
<span class="nt"><span</span> <span class="na">class=</span><span class="s">"hero-eyebrow"</span><span class="nt">></span>4th Generation Educator<span class="nt"></span></span>
<span class="nt"><h1></span>Brandon JP Lambert<span class="nt"></h1></span>
<span class="nt"><p</span> <span class="na">class=</span><span class="s">"hero-intro"</span><span class="nt">></span>
I teach languages. I build tools. I use AI to make both better.
<span class="nt"><strong></span>10 years in classrooms → 15 projects → 1 portfolio<span class="nt"></strong></span>
<span class="nt"></p></span>
<span class="nt"><div</span> <span class="na">class=</span><span class="s">"hero-stats"</span><span class="nt">></span>
<span class="nt"><div</span> <span class="na">class=</span><span class="s">"stat"</span><span class="nt">></span>
<span class="nt"><span</span> <span class="na">class=</span><span class="s">"stat-number"</span><span class="nt">></span>10<span class="nt"></span></span>
<span class="nt"><span</span> <span class="na">class=</span><span class="s">"stat-label"</span><span class="nt">></span>Years Teaching<span class="nt"></span></span>
<span class="nt"></div></span>
<span class="nt"><div</span> <span class="na">class=</span><span class="s">"stat"</span><span class="nt">></span>
<span class="nt"><span</span> <span class="na">class=</span><span class="s">"stat-number"</span><span class="nt">></span>15<span class="nt"></span></span>
<span class="nt"><span</span> <span class="na">class=</span><span class="s">"stat-label"</span><span class="nt">></span>AI Projects<span class="nt"></span></span>
<span class="nt"></div></span>
<span class="nt"><div</span> <span class="na">class=</span><span class="s">"stat"</span><span class="nt">></span>
<span class="nt"><span</span> <span class="na">class=</span><span class="s">"stat-number"</span><span class="nt">></span>B2<span class="nt"></span></span>
<span class="nt"><span</span> <span class="na">class=</span><span class="s">"stat-label"</span><span class="nt">></span>Spanish Level<span class="nt"></span></span>
<span class="nt"></div></span>
<span class="nt"></div></span>
<span class="nt"><div</span> <span class="na">class=</span><span class="s">"hero-actions"</span><span class="nt">></span>
<span class="nt"><a</span> <span class="na">href=</span><span class="s">"/work/philosophy/"</span> <span class="na">class=</span><span class="s">"btn btn-primary"</span><span class="nt">></span>My Teaching Approach →<span class="nt"></a></span>
<span class="nt"><a</span> <span class="na">href=</span><span class="s">"/ai-projects/"</span> <span class="na">class=</span><span class="s">"btn btn-secondary"</span><span class="nt">></span>See the Tools<span class="nt"></a></span>
<span class="nt"></div></span>
<span class="nt"></div></span>
<span class="nt"></section></span>
</code></pre></div></div>
<p><strong>Why better:</strong></p>
<ul>
<li>Asymmetric layout creates visual interest</li>
<li>Stats give concrete proof</li>
<li>Photo humanizes immediately</li>
<li>Clear value proposition</li>
</ul>
<h3 id="2-project-cards---create-hierarchy">2. Project Cards - Create Hierarchy</h3>
<p><strong>Current:</strong> All projects have equal visual weight</p>
<p><strong>Improved:</strong> Three tiers</p>
<h4 id="tier-1-featured-project-full-width">Tier 1: Featured Project (Full Width)</h4>
<div class="language-scss highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nc">.project-featured</span> <span class="p">{</span>
<span class="nl">display</span><span class="p">:</span> <span class="n">grid</span><span class="p">;</span>
<span class="na">grid-template-columns</span><span class="p">:</span> <span class="m">1</span><span class="mi">.5fr</span> <span class="m">1fr</span><span class="p">;</span>
<span class="na">gap</span><span class="p">:</span> <span class="nf">var</span><span class="p">(</span><span class="o">--</span><span class="n">space-6</span><span class="p">);</span>
<span class="nl">margin-bottom</span><span class="p">:</span> <span class="nf">var</span><span class="p">(</span><span class="o">--</span><span class="n">space-8</span><span class="p">);</span>
<span class="nl">padding</span><span class="p">:</span> <span class="nf">var</span><span class="p">(</span><span class="o">--</span><span class="n">space-6</span><span class="p">);</span>
<span class="nl">background</span><span class="p">:</span> <span class="nf">linear-gradient</span><span class="p">(</span><span class="m">135deg</span><span class="o">,</span> <span class="mh">#f5f7fa</span> <span class="m">0%</span><span class="o">,</span> <span class="mh">#c3cfe2</span> <span class="m">100%</span><span class="p">);</span>
<span class="nl">border-radius</span><span class="p">:</span> <span class="m">12px</span><span class="p">;</span>
<span class="nc">.project-gallery</span> <span class="p">{</span>
<span class="c1">// Large image carousel</span>
<span class="p">}</span>
<span class="nc">.project-details</span> <span class="p">{</span>
<span class="c1">// Prominent description, metrics, CTAs</span>
<span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>
<h4 id="tier-2-active-projects-2-column-grid">Tier 2: Active Projects (2 Column Grid)</h4>
<div class="language-scss highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nc">.project-active</span> <span class="p">{</span>
<span class="nl">display</span><span class="p">:</span> <span class="n">grid</span><span class="p">;</span>
<span class="na">grid-template-columns</span><span class="p">:</span> <span class="nf">repeat</span><span class="p">(</span><span class="m">2</span><span class="o">,</span> <span class="m">1fr</span><span class="p">);</span>
<span class="na">gap</span><span class="p">:</span> <span class="nf">var</span><span class="p">(</span><span class="o">--</span><span class="n">space-5</span><span class="p">);</span>
<span class="nc">.project-card</span> <span class="p">{</span>
<span class="c1">// Medium-sized cards</span>
<span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>
<h4 id="tier-3-prototypes-3-column-compact">Tier 3: Prototypes (3 Column, Compact)</h4>
<div class="language-scss highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nc">.project-prototype</span> <span class="p">{</span>
<span class="nl">display</span><span class="p">:</span> <span class="n">grid</span><span class="p">;</span>
<span class="na">grid-template-columns</span><span class="p">:</span> <span class="nf">repeat</span><span class="p">(</span><span class="m">3</span><span class="o">,</span> <span class="m">1fr</span><span class="p">);</span>
<span class="na">gap</span><span class="p">:</span> <span class="nf">var</span><span class="p">(</span><span class="o">--</span><span class="n">space-3</span><span class="p">);</span>
<span class="nc">.project-card</span> <span class="p">{</span>
<span class="c1">// Compact cards, less detail</span>
<span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>
<p><strong>Impact:</strong> Visitors immediately see what’s most important.</p>
<h3 id="3-color-palette---add-warmth--energy">3. Color Palette - Add Warmth & Energy</h3>
<p><strong>Current palette problems:</strong></p>
<ul>
<li>Too corporate</li>
<li>No warmth</li>
<li>No energy</li>
</ul>
<p><strong>Proposed alternative (inspired by your Colombia photography):</strong></p>
<div class="language-scss highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nd">:root</span> <span class="p">{</span>
<span class="c1">// Primary (keep some blue, warm it up)</span>
<span class="na">--color-primary</span><span class="p">:</span> <span class="mh">#2B6CB0</span><span class="p">;</span> <span class="c1">// Warmer blue</span>
<span class="na">--color-primary-dark</span><span class="p">:</span> <span class="mh">#1A4971</span><span class="p">;</span>
<span class="na">--color-primary-light</span><span class="p">:</span> <span class="mh">#4299E1</span><span class="p">;</span>
<span class="c1">// Secondary (add warm accent)</span>
<span class="na">--color-secondary</span><span class="p">:</span> <span class="mh">#DD6B20</span><span class="p">;</span> <span class="c1">// Warm orange (Colombia sunset)</span>
<span class="c1">// Tertiary (education green)</span>
<span class="na">--color-tertiary</span><span class="p">:</span> <span class="mh">#38A169</span><span class="p">;</span> <span class="c1">// Success/growth green</span>
<span class="c1">// Neutrals (warmer)</span>
<span class="na">--color-ink</span><span class="p">:</span> <span class="mh">#2D3748</span><span class="p">;</span> <span class="c1">// Softer than pure black</span>
<span class="na">--color-paper</span><span class="p">:</span> <span class="mh">#FFFAF0</span><span class="p">;</span> <span class="c1">// Warmer white (slight cream)</span>
<span class="c1">// Supporting</span>
<span class="na">--color-accent</span><span class="p">:</span> <span class="mh">#9F7AEA</span><span class="p">;</span> <span class="c1">// Purple for variety</span>
<span class="na">--color-muted</span><span class="p">:</span> <span class="mh">#718096</span><span class="p">;</span> <span class="c1">// Keep this</span>
<span class="p">}</span>
</code></pre></div></div>
<p><strong>Color usage:</strong></p>
<ul>
<li><strong>Primary blue</strong>: Main CTAs, links</li>
<li><strong>Secondary orange</strong>: Important accents, featured elements</li>
<li><strong>Tertiary green</strong>: Success states, completed projects</li>
<li><strong>Purple</strong>: Hover states, subtle highlights</li>
</ul>
<p><strong>Why better:</strong></p>
<ul>
<li>Warm colors are inviting</li>
<li>Orange adds energy</li>
<li>Green connects to education/growth theme</li>
<li>Still professional, but memorable</li>
</ul>
<h3 id="4-typography---add-personality">4. Typography - Add Personality</h3>
<p><strong>Current fonts are fine</strong>, but could be more distinctive:</p>
<p><strong>Alternative 1: Embrace the Academic</strong></p>
<div class="language-scss highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="na">--font-heading</span><span class="p">:</span> <span class="s1">'Crimson Pro'</span><span class="o">,</span> <span class="s1">'Crimson Text'</span><span class="o">,</span> <span class="n">Georgia</span><span class="o">,</span> <span class="nb">serif</span><span class="p">;</span>
<span class="na">--font-body</span><span class="p">:</span> <span class="s1">'Inter'</span><span class="o">,</span> <span class="nb">sans-serif</span><span class="p">;</span>
<span class="na">--font-accent</span><span class="p">:</span> <span class="s1">'Playfair Display'</span><span class="o">,</span> <span class="nb">serif</span><span class="p">;</span> <span class="c1">// For callouts</span>
</code></pre></div></div>
<p>Use Playfair Display for pull quotes, section headers</p>
<p><strong>Alternative 2: Modern Geometric</strong></p>
<div class="language-scss highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="na">--font-heading</span><span class="p">:</span> <span class="s1">'Poppins'</span><span class="o">,</span> <span class="nb">sans-serif</span><span class="p">;</span> <span class="c1">// Geometric, friendly</span>
<span class="na">--font-body</span><span class="p">:</span> <span class="s1">'Inter'</span><span class="o">,</span> <span class="nb">sans-serif</span><span class="p">;</span>
<span class="na">--font-accent</span><span class="p">:</span> <span class="s1">'Space Mono'</span><span class="o">,</span> <span class="nb">monospace</span><span class="p">;</span> <span class="c1">// For code/tech elements</span>
</code></pre></div></div>
<p><strong>Alternative 3: Humanist (warm, approachable)</strong></p>
<div class="language-scss highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="na">--font-heading</span><span class="p">:</span> <span class="s1">'Merriweather'</span><span class="o">,</span> <span class="nb">serif</span><span class="p">;</span>
<span class="na">--font-body</span><span class="p">:</span> <span class="s1">'Source Sans Pro'</span><span class="o">,</span> <span class="nb">sans-serif</span><span class="p">;</span>
<span class="na">--font-accent</span><span class="p">:</span> <span class="s1">'Bitter'</span><span class="o">,</span> <span class="nb">serif</span><span class="p">;</span> <span class="c1">// For emphasis</span>
</code></pre></div></div>
<p><strong>Recommendation:</strong> Stick with current, but add <strong>typographic variety</strong>:</p>
<ul>
<li>Use italic Crimson Text for pull quotes</li>
<li>Add larger font sizes for important statements</li>
<li>Increase line-height for readability (current: 1.6, try 1.8)</li>
</ul>
<h3 id="5-micro-interactions---add-delight">5. Micro-Interactions - Add Delight</h3>
<p><strong>Current interactions:</strong> Hover color changes, translateY(-2px)</p>
<p><strong>Opportunities:</strong></p>
<h4 id="navigation-hover">Navigation Hover</h4>
<div class="language-scss highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nc">.site-nav</span> <span class="nt">a</span> <span class="p">{</span>
<span class="nl">position</span><span class="p">:</span> <span class="nb">relative</span><span class="p">;</span>
<span class="k">&</span><span class="nd">::after</span> <span class="p">{</span>
<span class="nl">content</span><span class="p">:</span> <span class="s1">''</span><span class="p">;</span>
<span class="nl">position</span><span class="p">:</span> <span class="nb">absolute</span><span class="p">;</span>
<span class="nl">bottom</span><span class="p">:</span> <span class="m">-2px</span><span class="p">;</span>
<span class="nl">left</span><span class="p">:</span> <span class="m">0</span><span class="p">;</span>
<span class="nl">width</span><span class="p">:</span> <span class="m">0</span><span class="p">;</span>
<span class="nl">height</span><span class="p">:</span> <span class="m">2px</span><span class="p">;</span>
<span class="nl">background</span><span class="p">:</span> <span class="nf">var</span><span class="p">(</span><span class="o">--</span><span class="n">color-primary</span><span class="p">);</span>
<span class="nl">transition</span><span class="p">:</span> <span class="n">width</span> <span class="m">0</span><span class="mi">.3s</span> <span class="n">ease</span><span class="p">;</span>
<span class="p">}</span>
<span class="k">&</span><span class="nd">:hover::after</span> <span class="p">{</span>
<span class="nl">width</span><span class="p">:</span> <span class="m">100%</span><span class="p">;</span>
<span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>
<h4 id="project-card-hover">Project Card Hover</h4>
<div class="language-scss highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nc">.project-card</span> <span class="p">{</span>
<span class="nl">transition</span><span class="p">:</span> <span class="n">all</span> <span class="m">0</span><span class="mi">.3s</span> <span class="n">ease</span><span class="p">;</span>
<span class="k">&</span><span class="nd">:hover</span> <span class="p">{</span>
<span class="nl">transform</span><span class="p">:</span> <span class="nf">translateY</span><span class="p">(</span><span class="m">-4px</span><span class="p">)</span> <span class="nf">scale</span><span class="p">(</span><span class="m">1</span><span class="mi">.02</span><span class="p">);</span>
<span class="nl">box-shadow</span><span class="p">:</span> <span class="m">0</span> <span class="m">12px</span> <span class="m">24px</span> <span class="nf">rgba</span><span class="p">(</span><span class="m">0</span><span class="o">,</span><span class="m">0</span><span class="o">,</span><span class="m">0</span><span class="o">,</span><span class="m">0</span><span class="mi">.15</span><span class="p">);</span>
<span class="nc">.project-image</span> <span class="nt">img</span> <span class="p">{</span>
<span class="nl">transform</span><span class="p">:</span> <span class="nf">scale</span><span class="p">(</span><span class="m">1</span><span class="mi">.05</span><span class="p">);</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>
<h4 id="button-press">Button Press</h4>
<div class="language-scss highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nc">.btn</span> <span class="p">{</span>
<span class="k">&</span><span class="nd">:active</span> <span class="p">{</span>
<span class="nl">transform</span><span class="p">:</span> <span class="nf">translateY</span><span class="p">(</span><span class="m">1px</span><span class="p">);</span>
<span class="nl">box-shadow</span><span class="p">:</span> <span class="nb">inset</span> <span class="m">0</span> <span class="m">2px</span> <span class="m">4px</span> <span class="nf">rgba</span><span class="p">(</span><span class="m">0</span><span class="o">,</span><span class="m">0</span><span class="o">,</span><span class="m">0</span><span class="o">,</span><span class="m">0</span><span class="mi">.1</span><span class="p">);</span>
<span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>
<p><strong>Small changes, big impact</strong> on perceived quality.</p>
<h2 id="ux-issues-to-fix">UX Issues to Fix</h2>
<h3 id="1-mobile-menu-implementation">1. <strong>Mobile Menu Implementation</strong></h3>
<p><strong>Current</strong> (_layouts/default.html, lines 85-89):</p>
<div class="language-html highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt"><button</span> <span class="na">class=</span><span class="s">"mobile-menu-toggle"</span> <span class="na">onclick=</span><span class="s">"toggleMobileMenu()"</span><span class="nt">></span>
<span class="nt"><span></span></span>
<span class="nt"><span></span></span>
<span class="nt"><span></span></span>
<span class="nt"></button></span>
</code></pre></div></div>
<p><strong>Problems:</strong></p>
<ul>
<li>Hamburger icon without label (accessibility issue)</li>
<li>No visual feedback on menu state</li>
<li>JavaScript inline in HTML</li>
</ul>
<p><strong>Better:</strong></p>
<div class="language-html highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt"><button</span> <span class="na">class=</span><span class="s">"mobile-menu-toggle"</span>
<span class="na">aria-label=</span><span class="s">"Toggle menu"</span>
<span class="na">aria-expanded=</span><span class="s">"false"</span>
<span class="na">aria-controls=</span><span class="s">"mobile-menu"</span><span class="nt">></span>
<span class="nt"><span</span> <span class="na">class=</span><span class="s">"hamburger"</span><span class="nt">></span>
<span class="nt"><span</span> <span class="na">class=</span><span class="s">"hamburger-line"</span><span class="nt">></span></span>
<span class="nt"><span</span> <span class="na">class=</span><span class="s">"hamburger-line"</span><span class="nt">></span></span>
<span class="nt"><span</span> <span class="na">class=</span><span class="s">"hamburger-line"</span><span class="nt">></span></span>
<span class="nt"></span></span>
<span class="nt"><span</span> <span class="na">class=</span><span class="s">"sr-only"</span><span class="nt">></span>Menu<span class="nt"></span></span>
<span class="nt"></button></span>
</code></pre></div></div>
<p><strong>With CSS animation:</strong></p>
<div class="language-scss highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nc">.mobile-menu-toggle</span> <span class="p">{</span>
<span class="k">&</span><span class="o">[</span><span class="nt">aria-expanded</span><span class="o">=</span><span class="s2">"true"</span><span class="o">]</span> <span class="p">{</span>
<span class="nc">.hamburger-line</span><span class="nd">:nth-child</span><span class="o">(</span><span class="nt">1</span><span class="o">)</span> <span class="p">{</span>
<span class="nl">transform</span><span class="p">:</span> <span class="nf">rotate</span><span class="p">(</span><span class="m">45deg</span><span class="p">)</span> <span class="nf">translate</span><span class="p">(</span><span class="m">5px</span><span class="o">,</span> <span class="m">5px</span><span class="p">);</span>
<span class="p">}</span>
<span class="nc">.hamburger-line</span><span class="nd">:nth-child</span><span class="o">(</span><span class="nt">2</span><span class="o">)</span> <span class="p">{</span>
<span class="nl">opacity</span><span class="p">:</span> <span class="m">0</span><span class="p">;</span>
<span class="p">}</span>
<span class="nc">.hamburger-line</span><span class="nd">:nth-child</span><span class="o">(</span><span class="nt">3</span><span class="o">)</span> <span class="p">{</span>
<span class="nl">transform</span><span class="p">:</span> <span class="nf">rotate</span><span class="p">(</span><span class="m">-45deg</span><span class="p">)</span> <span class="nf">translate</span><span class="p">(</span><span class="m">5px</span><span class="o">,</span> <span class="m">-5px</span><span class="p">);</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>
<p><strong>Animated hamburger → X</strong> is expected UX.</p>
<h3 id="2-language-switcher-visibility">2. <strong>Language Switcher Visibility</strong></h3>
<p><strong>Current</strong> (_layouts/default.html, lines 75-82):</p>
<div class="language-html highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt"><div</span> <span class="na">class=</span><span class="s">"language-toggle"</span><span class="nt">></span>
<span class="nt"><button</span> <span class="na">class=</span><span class="s">"lang-btn"</span> <span class="na">data-lang=</span><span class="s">"en"</span><span class="nt">></span>EN<span class="nt"></button></span>
<span class="nt"><button</span> <span class="na">class=</span><span class="s">"lang-btn"</span> <span class="na">data-lang=</span><span class="s">"es"</span><span class="nt">></span>ES<span class="nt"></button></span>
<span class="nt"></div></span>
</code></pre></div></div>
<p><strong>Problems:</strong></p>
<ul>
<li>Small buttons, easy to miss</li>
<li>No indication which is active (requires JS)</li>
<li>No flags or clear visual differentiation</li>
</ul>
<p><strong>Better:</strong></p>
<div class="language-html highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt"><div</span> <span class="na">class=</span><span class="s">"language-toggle"</span> <span class="na">role=</span><span class="s">"group"</span> <span class="na">aria-label=</span><span class="s">"Language selection"</span><span class="nt">></span>
<span class="nt"><button</span> <span class="na">class=</span><span class="s">"lang-btn"</span> <span class="na">data-lang=</span><span class="s">"en"</span> <span class="na">aria-pressed=</span><span class="s">"true"</span><span class="nt">></span>
<span class="nt"><span</span> <span class="na">class=</span><span class="s">"flag"</span><span class="nt">></span>🇺🇸<span class="nt"></span></span>
<span class="nt"><span</span> <span class="na">class=</span><span class="s">"lang-label"</span><span class="nt">></span>English<span class="nt"></span></span>
<span class="nt"></button></span>
<span class="nt"><button</span> <span class="na">class=</span><span class="s">"lang-btn"</span> <span class="na">data-lang=</span><span class="s">"es"</span> <span class="na">aria-pressed=</span><span class="s">"false"</span><span class="nt">></span>
<span class="nt"><span</span> <span class="na">class=</span><span class="s">"flag"</span><span class="nt">></span>🇪🇸<span class="nt"></span></span>
<span class="nt"><span</span> <span class="na">class=</span><span class="s">"lang-label"</span><span class="nt">></span>Español<span class="nt"></span></span>
<span class="nt"></button></span>
<span class="nt"></div></span>
</code></pre></div></div>
<p><strong>With styles:</strong></p>
<div class="language-scss highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nc">.lang-btn</span> <span class="p">{</span>
<span class="k">&</span><span class="o">[</span><span class="nt">aria-pressed</span><span class="o">=</span><span class="s2">"true"</span><span class="o">]</span> <span class="p">{</span>
<span class="nl">background</span><span class="p">:</span> <span class="nf">var</span><span class="p">(</span><span class="o">--</span><span class="n">color-primary</span><span class="p">);</span>
<span class="nl">color</span><span class="p">:</span> <span class="no">white</span><span class="p">;</span>
<span class="nl">font-weight</span><span class="p">:</span> <span class="m">600</span><span class="p">;</span>
<span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>
<p><strong>Flags + labels + clear active state</strong> = better UX.</p>
<h3 id="3-project-filtering-feedback">3. <strong>Project Filtering Feedback</strong></h3>
<p><strong>Current</strong> (ai-projects.html, lines 11-19):</p>
<ul>
<li>Buttons change color when active</li>
<li>No count of filtered results</li>
<li>No empty state message</li>
</ul>
<p><strong>Improved:</strong></p>
<div class="language-html highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt"><div</span> <span class="na">class=</span><span class="s">"filter-controls"</span><span class="nt">></span>
<span class="nt"><button</span> <span class="na">class=</span><span class="s">"filter-btn active"</span> <span class="na">data-filter=</span><span class="s">"all"</span><span class="nt">></span>
All Projects <span class="nt"><span</span> <span class="na">class=</span><span class="s">"count"</span><span class="nt">></span>(15)<span class="nt"></span></span>
<span class="nt"></button></span>
<span class="nt"><button</span> <span class="na">class=</span><span class="s">"filter-btn"</span> <span class="na">data-filter=</span><span class="s">"Educational"</span><span class="nt">></span>
Educational <span class="nt"><span</span> <span class="na">class=</span><span class="s">"count"</span><span class="nt">></span>(8)<span class="nt"></span></span>
<span class="nt"></button></span>
<span class="c"><!-- etc --></span>
<span class="nt"></div></span>
<span class="nt"><div</span> <span class="na">class=</span><span class="s">"filter-results"</span><span class="nt">></span>
<span class="nt"><p></span>Showing <span class="nt"><strong</span> <span class="na">id=</span><span class="s">"results-count"</span><span class="nt">></span>15<span class="nt"></strong></span> projects<span class="nt"></p></span>
<span class="nt"></div></span>
</code></pre></div></div>
<p><strong>JavaScript updates count</strong> when filtering. Users get immediate feedback.</p>
<h3 id="4-missing-loading-states">4. <strong>Missing Loading States</strong></h3>
<p><strong>Current:</strong> No loading indicators for:</p>
<ul>
<li>Image lazy loading</li>
<li>Page transitions</li>
<li>AJAX (if any)</li>
</ul>
<p><strong>Add:</strong></p>
<div class="language-html highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt"><div</span> <span class="na">class=</span><span class="s">"project-image"</span><span class="nt">></span>
<span class="nt"><img</span> <span class="na">src=</span><span class="s">"project.jpg"</span>
<span class="na">loading=</span><span class="s">"lazy"</span>
<span class="na">alt=</span><span class="s">"..."</span>
<span class="na">onload=</span><span class="s">"this.classList.add('loaded')"</span><span class="nt">></span>
<span class="nt"><div</span> <span class="na">class=</span><span class="s">"image-loader"</span><span class="nt">></div></span>
<span class="nt"></div></span>
</code></pre></div></div>
<div class="language-scss highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nc">.project-image</span> <span class="p">{</span>
<span class="nl">position</span><span class="p">:</span> <span class="nb">relative</span><span class="p">;</span>
<span class="nt">img</span> <span class="p">{</span>
<span class="nl">opacity</span><span class="p">:</span> <span class="m">0</span><span class="p">;</span>
<span class="nl">transition</span><span class="p">:</span> <span class="n">opacity</span> <span class="m">0</span><span class="mi">.3s</span><span class="p">;</span>
<span class="k">&</span><span class="nc">.loaded</span> <span class="p">{</span>
<span class="nl">opacity</span><span class="p">:</span> <span class="m">1</span><span class="p">;</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="nc">.image-loader</span> <span class="p">{</span>
<span class="nl">position</span><span class="p">:</span> <span class="nb">absolute</span><span class="p">;</span>
<span class="na">inset</span><span class="p">:</span> <span class="m">0</span><span class="p">;</span>
<span class="nl">background</span><span class="p">:</span> <span class="nf">linear-gradient</span><span class="p">(</span><span class="m">90deg</span><span class="o">,</span> <span class="mh">#f0f0f0</span> <span class="m">25%</span><span class="o">,</span> <span class="mh">#e0e0e0</span> <span class="m">50%</span><span class="o">,</span> <span class="mh">#f0f0f0</span> <span class="m">75%</span><span class="p">);</span>
<span class="nl">background-size</span><span class="p">:</span> <span class="m">200%</span> <span class="m">100%</span><span class="p">;</span>
<span class="nl">animation</span><span class="p">:</span> <span class="n">loading</span> <span class="m">1</span><span class="mi">.5s</span> <span class="n">infinite</span><span class="p">;</span>
<span class="p">}</span>
<span class="nt">img</span><span class="nc">.loaded</span> <span class="o">~</span> <span class="nc">.image-loader</span> <span class="p">{</span>
<span class="nl">display</span><span class="p">:</span> <span class="nb">none</span><span class="p">;</span>
<span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>
<p><strong>Skeleton loaders</strong> improve perceived performance.</p>
<h2 id="design-inspiration-sources">Design Inspiration Sources</h2>
<h3 id="portfolios-with-personality">Portfolios with Personality</h3>
<ul>
<li><strong>Cassie Evans</strong> (cassie.codes) - Playful animations, hand-drawn elements</li>
<li><strong>Lynn Fisher</strong> (lynnandtonic.com) - Unique layout each year, creative constraints</li>
<li><strong>Tatiana Mac</strong> (tatianamac.com) - Strong typography, clear voice</li>
<li><strong>Dan Abramov</strong> (overreacted.io) - Content-first, personality in writing</li>
</ul>
<h3 id="key-takeaways-from-each">Key Takeaways from Each</h3>
<ul>
<li><strong>Cassie</strong>: Animation can show personality without being distracting</li>
<li><strong>Lynn</strong>: Constraints breed creativity (she redesigns yearly with a theme)</li>
<li><strong>Tatiana</strong>: Strong opinions, strongly held (design reflects confidence)</li>
<li><strong>Dan</strong>: Content quality matters more than flashy design</li>
</ul>
<p><strong>Your opportunity:</strong> Combine educator authenticity with creative visual expression.</p>
<h2 id="action-plan-design-improvements">Action Plan: Design Improvements</h2>
<h3 id="week-1-quick-visual-wins-6-8-hours">Week 1: Quick Visual Wins (6-8 hours)</h3>
<p><strong>Day 1: Color Palette Refresh</strong> (2 hours)</p>
<ul>
<li>Update _variables.scss with warmer colors</li>
<li>Test contrast ratios (WebAIM tool)</li>
<li>Apply to buttons and accents</li>
</ul>
<p><strong>Day 2: Hero Section Redesign</strong> (3 hours)</p>
<ul>
<li>Add personal photo</li>
<li>Create asymmetric layout</li>
<li>Add stats/metrics</li>
<li>Rewrite CTA buttons</li>
</ul>
<p><strong>Day 3: Project Card Hierarchy</strong> (2 hours)</p>
<ul>
<li>Pick 1 featured project (full width)</li>
<li>Adjust grid for Active vs Prototype projects</li>
<li>Add visual differentiation</li>
</ul>
<h3 id="week-2-personality--polish-8-10-hours">Week 2: Personality & Polish (8-10 hours)</h3>
<p><strong>Day 4: Photography Integration</strong> (3 hours)</p>
<ul>
<li>Select 5-10 best photos from Letratos</li>
<li>Add as section backgrounds (with overlay)</li>
<li>Create photo gallery on homepage</li>
<li>Link to Letratos prominently</li>
</ul>
<p><strong>Day 5: Micro-Interactions</strong> (2 hours)</p>
<ul>
<li>Improve button hover states</li>
<li>Add nav underline animation</li>
<li>Animate mobile menu icon</li>
<li>Polish project card hovers</li>
</ul>
<p><strong>Day 6: Typography Refinement</strong> (2 hours)</p>
<ul>
<li>Increase body line-height to 1.8</li>
<li>Add pull quote styling (large, italic, Crimson)</li>
<li>Create visual hierarchy in project descriptions</li>
<li>Add section header treatments</li>
</ul>
<p><strong>Day 7: UX Fixes</strong> (2 hours)</p>
<ul>
<li>Fix mobile menu accessibility</li>
<li>Improve language switcher visibility</li>
<li>Add loading states for images</li>
<li>Add filter result counts</li>
</ul>
<h3 id="month-1-major-redesign-elements-16-20-hours">Month 1: Major Redesign Elements (16-20 hours)</h3>
<p><strong>Week 3: Teaching Timeline</strong> (6 hours)</p>
<ul>
<li>Design visual timeline of 4 generations</li>
<li>Source family photos (if available)</li>
<li>Create illustrated version if no photos</li>
<li>Add to “About” or “Work” page</li>
</ul>
<p><strong>Week 4: Bilingual Design Elements</strong> (6 hours)</p>
<ul>
<li>Add Spanish idioms as section headers</li>
<li>Create bilingual typography treatments</li>
<li>Add cultural color references</li>
<li>Design language-specific layouts</li>
</ul>
<p><strong>Week 5: Project Case Studies</strong> (8 hours)</p>
<ul>
<li>Choose top 3 projects</li>
<li>Create detailed visual case study layout</li>
<li>Include process images, iterations, metrics</li>
<li>Design unique layout for each</li>
</ul>
<h2 id="success-metrics-design">Success Metrics (Design)</h2>
<h3 id="beforeafter-comparison">Before/After Comparison</h3>
<p><strong>Test:</strong> Show 5 people your portfolio for 30 seconds. After, ask:</p>
<p><strong>Current responses (predicted):</strong></p>
<ul>
<li>“It’s clean”</li>
<li>“Professional”</li>
<li>“Blue and white”</li>
<li>“Developer portfolio”</li>
</ul>
<p><strong>Goal responses:</strong></p>
<ul>
<li>“The teaching timeline is really cool”</li>
<li>“I love the photo of you teaching”</li>
<li>“The orange accent is warm”</li>
<li>“An educator who codes—that’s unique”</li>
</ul>
<p><strong>If responses change</strong> → design is working.</p>
<h3 id="specific-metrics">Specific Metrics</h3>
<p><strong>Visual Variety</strong></p>
<ul>
<li>Current: All project cards identical</li>
<li>Goal: 3 distinct card layouts (featured, active, prototype)</li>
</ul>
<p><strong>Color Usage</strong></p>
<ul>
<li>Current: 90% gray/blue, 10% accent</li>
<li>Goal: 70% neutral, 20% primary, 10% warm accents</li>
</ul>
<p><strong>Personal Elements</strong></p>
<ul>
<li>Current: 1 (avatar)</li>
<li>Goal: 5+ (photos, teaching artifacts, family history)</li>
</ul>
<p><strong>Memorable Moments</strong></p>
<ul>
<li>Current: 0</li>
<li>Goal: 3-5 (timeline, photo gallery, unique layout, Easter egg)</li>
</ul>
<h2 id="final-thought-on-design">Final Thought on Design</h2>
<p><strong>Your design isn’t bad. It’s boring.</strong></p>
<p>And “boring” is worse than “bad” because:</p>
<ul>
<li>Bad design gets remembered (even negatively)</li>
<li>Boring design gets forgotten</li>
</ul>
<p>You have <strong>unique stories</strong> (4 generations of teaching, learning Spanish, Colombia experience, building 15 projects).</p>
<p>Your design should <strong>reflect those stories visually</strong>.</p>
<p><strong>Stop designing like you’re applying for a corporate job.</strong></p>
<p><strong>Start designing like you’re starting a conversation.</strong></p>
<p>The technical foundation is solid. Now add personality, warmth, and visual storytelling.</p>
<p>Start with the hero section redesign. You’ll feel the difference immediately.</p>
</div>
</div>
</article>
</main>
<footer class="site-footer">
<!-- Footer content -->
</footer>
Good practices:
- ✅ Proper
<header>,<nav>,<main>,<footer>structure - ✅ Skip-to-content link for keyboard navigation
- ✅ ARIA labels on interactive elements
- ✅ Semantic heading hierarchy
One issue: Mobile menu has accessibility problems (covered later).
3. SEO & Meta Tags (8.5/10)
From _layouts/default.html (lines 8-29):
<!-- SEO Meta Tags -->
<!-- Begin Jekyll SEO tag v2.8.0 -->
<title>Technical Implementation Review | Brandon JP Lambert</title>
<meta name="generator" content="Jekyll v3.10.0" />
<meta property="og:title" content="Technical Implementation Review" />
<meta name="author" content="Brandon JP Lambert" />
<meta property="og:locale" content="en" />
<meta name="description" content="Academic portfolio and educational resource platform showcasing work in education, technology, and language learning. Bilingual English/Spanish site featuring AI projects, teaching philosophy, and Spanish learning resources." />
<meta property="og:description" content="Academic portfolio and educational resource platform showcasing work in education, technology, and language learning. Bilingual English/Spanish site featuring AI projects, teaching philosophy, and Spanish learning resources." />
<link rel="canonical" href="https://brandonjplambert.com/docs/portfolio-review/03-technical-implementation/" />
<meta property="og:url" content="https://brandonjplambert.com/docs/portfolio-review/03-technical-implementation/" />
<meta property="og:site_name" content="Brandon JP Lambert" />
<meta property="og:type" content="website" />
<meta name="twitter:card" content="summary" />
<meta property="twitter:title" content="Technical Implementation Review" />
<script type="application/ld+json">
{"@context":"https://schema.org","@type":"WebPage","author":{"@type":"Person","name":"Brandon JP Lambert"},"description":"Academic portfolio and educational resource platform showcasing work in education, technology, and language learning. Bilingual English/Spanish site featuring AI projects, teaching philosophy, and Spanish learning resources.","headline":"Technical Implementation Review","url":"https://brandonjplambert.com/docs/portfolio-review/03-technical-implementation/"}</script>
<!-- End Jekyll SEO tag -->
<!-- Alternate language versions -->
<link rel="alternate" hreflang="en" href="https://brandonjplambert.com/docs/portfolio-review/03-technical-implementation/">
<link rel="alternate" hreflang="es" href="https://brandonjplambert.com/es/docs/portfolio-review/03-technical-implementation/">
<link rel="alternate" hreflang="x-default" href="https://brandonjplambert.com/docs/portfolio-review/03-technical-implementation/">
<!-- Fonts with preconnect -->
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<!-- Favicon -->
<link rel="icon" type="image/png" sizes="32x32" href="...">
<!-- Feed -->
<link rel="alternate" type="application/rss+xml" title="Brandon JP Lambert" href="/feed.xml">
Good practices:
- ✅ Using
jekyll-seo-tagplugin - ✅ Proper hreflang tags for bilingual content
- ✅ Font preconnect for performance
- ✅ RSS feed available
- ✅ Cache busting with timestamps (line 22)
One issue: Google Fonts are render-blocking. Consider self-hosting or font-display: swap.
4. Performance Considerations (8/10)
From _config.yml (lines 58-60):
sass:
style: compressed
sass_dir: _sass
From _layouts/default.html (line 22):
<link rel="stylesheet" href="/assets/css/main.css?v=1762906844">
From _pages/ai-projects.html (line 43):
<img src="" alt="..." loading="lazy">
Good practices:
- ✅ Compressed SASS output
- ✅ Cache busting on CSS
- ✅ Lazy loading images
- ✅ No unnecessary JavaScript libraries
Performance score prediction: Lighthouse 90-95
Improvements possible:
- Critical CSS inlining
- Image optimization (WebP with fallbacks)
- Service worker for offline support
- Font subsetting (only load characters you use)
5. Accessibility (8/10)
Good elements:
<!-- ARIA labels -->
<button aria-label="Toggle menu">...</button>
<button aria-label="Switch to English">...</button>
<!-- Skip link -->
<a href="#main" class="sr-only">Skip to main content</a>
<!-- Semantic structure -->
<nav aria-label="Primary navigation">...</nav>
From _sass/_variables.scss (lines 4-12):
// High contrast colors
--color-ink: #1a1a1a; // Dark enough for WCAG AAA
--color-paper: #fafaf9; // Light enough for contrast
--color-accent: #2c5282; // Passes WCAG AA on white
Accessibility strengths:
- ✅ Good color contrast
- ✅ Semantic HTML
- ✅ Keyboard navigation support
- ✅ Skip links
- ✅ ARIA labels where needed
Issues:
- ❌ Mobile menu missing
aria-expandedstate - ❌ No focus indicators visible (keyboard navigation unclear)
- ❌ Some interactive elements use
onclickinstead of proper event listeners - ❌ No reduced-motion media query support
Technical Debt Identified
✅ RESOLVED Oct 8, 2025 - Inline JavaScript in Templates
Problem 1: 346 Lines of JavaScript in HTML → FIXED
File: _pages/ai-projects.html (lines 152-498) → Now 167 lines total
Resolution (Oct 8, 2025):
- ✅ Extracted to 4 focused modules in
/assets/js/ - ✅ projects-filter.js (117 lines)
- ✅ project-modal.js (113 lines)
- ✅ tech-tooltips.js (115 lines)
- ✅ site-navigation.js (171 lines)
- ✅ Result: 994 → 167 lines (-83% reduction)
- ✅ See: daily_reports/2025-10-08.md for full details
Original Problems (NOW FIXED):
Untestable- Now modular and testableNo minification- Can now minify separatelyNo linting- Modules can be lintedHard to debug- Clear module boundariesViolates separation of concerns- Proper separation achieved
Current structure:
<script>
(function() {
'use strict';
// 346 lines of project filtering logic
// 200+ lines of modal logic
// 50+ lines of tooltip logic
})();
</script>
Should be:
/assets/js/
├── projects-filter.js (filtering logic)
├── project-modal.js (history modal)
├── tech-tooltips.js (tooltip interactions)
└── main.js (initialization)
Impact: Medium effort (4-6 hours), high value (maintainability)
✅ RESOLVED Oct 8, 2025 - Navigation Duplication → FIXED
File: _layouts/default.html (lines 40-93 and 96-133)
Resolution (Oct 8, 2025):
- ✅ Created
_includes/nav-items.html(single source of truth) - ✅ Eliminated 56 lines of duplication
- ✅ DRY principle applied (Don’t Repeat Yourself)
- ✅ Navigation logic now reusable
- ✅ default.html reduced from 332 → 130 lines (-61%)
You have two complete navigation structures: → NOW: Single navigation include
Current Architecture:
<!-- Desktop nav (3 lines) -->
<li>
<a href="/"
>
Home
</a>
</li>
<li>
<a href="/work/"
>
Work
</a>
</li>
<li>
<a href="/ai-projects/"
>
AI Projects
</a>
</li>
<li>
<a href="/resources/"
>
Resources
</a>
</li>
<li>
<a href="/contact/"
>
Contact
</a>
</li>
<!-- Mobile nav (8 lines with parameter) -->
<li class="mobile-nav-item">
<a href="/"
onclick="closeMobileMenu()">
Home
</a>
</li>
<li class="mobile-nav-item">
<a href="/work/"
onclick="closeMobileMenu()">
Work
</a>
</li>
<li class="mobile-nav-item">
<a href="/ai-projects/"
onclick="closeMobileMenu()">
AI Projects
</a>
</li>
<li class="mobile-nav-item">
<a href="/resources/"
onclick="closeMobileMenu()">
Resources
</a>
</li>
<li class="mobile-nav-item">
<a href="/contact/"
onclick="closeMobileMenu()">
Contact
</a>
</li>
Original Problems (NOW FIXED):
Any nav change requires updating two places- Now single includeIncreases HTML size (duplicated markup)- Eliminated duplicationHigher chance of inconsistencies- Single source prevents mismatches
Solution: Single nav, CSS-controlled visibility:
<nav class="site-nav" id="site-nav">
<ul class="nav-list">
<li class="nav-item">
<a href="..." class="nav-link"></a>
</li>
<li class="nav-item">
<a href="..." class="nav-link"></a>
</li>
<li class="nav-item">
<a href="..." class="nav-link"></a>
</li>
<li class="nav-item">
<a href="..." class="nav-link"></a>
</li>
<li class="nav-item">
<a href="..." class="nav-link"></a>
</li>
</ul>
</nav>
.site-nav {
// Desktop styles
@media (max-width: 1023px) {
// Mobile styles (full-screen overlay)
position: fixed;
top: 60px;
left: 0;
right: 0;
bottom: 0;
background: white;
opacity: 0;
pointer-events: none;
transition: opacity 0.3s;
&.is-open {
opacity: 1;
pointer-events: auto;
}
.nav-list {
flex-direction: column;
align-items: center;
justify-content: center;
height: 100%;
}
}
}
Impact: Low effort (2 hours), medium value (maintainability)
Problem 3: Imperative DOM Manipulation
File: _layouts/default.html (lines 177-213)
function toggleMobileMenu() {
const overlay = document.getElementById('mobile-menu-overlay');
const toggle = document.querySelector('.mobile-menu-toggle');
if (!overlay || !toggle) {
return;
}
// Check if menu is open
const isOpen = overlay.style.display === 'block';
if (!isOpen) {
// Open menu
overlay.style.display = 'block';
toggle.classList.add('active');
document.body.style.overflow = 'hidden';
} else {
// Close menu
overlay.style.display = 'none';
toggle.classList.remove('active');
document.body.style.overflow = '';
}
}
Problems:
- Manipulating
style.displaydirectly - Hard to test, brittle - Checking
style.displayto determine state - Doesn’t reflect actual state - Inline styles mixed with classes - Inconsistent approach
- Global function - Pollutes namespace
Modern approach using data attributes:
<button class="mobile-menu-toggle"
data-mobile-menu-toggle
aria-expanded="false"
aria-controls="site-nav">
<span class="hamburger">...</span>
</button>
<nav class="site-nav" id="site-nav" data-mobile-menu>
<!-- Navigation -->
</nav>
// /assets/js/mobile-menu.js
class MobileMenu {
constructor(toggleEl, menuEl) {
this.toggle = toggleEl;
this.menu = menuEl;
this.isOpen = false;
this.toggle.addEventListener('click', () => this.toggleMenu());
this.menu.addEventListener('click', (e) => {
if (e.target.matches('a')) {
this.closeMenu();
}
});
}
toggleMenu() {
this.isOpen ? this.closeMenu() : this.openMenu();
}
openMenu() {
this.isOpen = true;
this.menu.classList.add('is-open');
this.toggle.setAttribute('aria-expanded', 'true');
document.body.classList.add('menu-open');
}
closeMenu() {
this.isOpen = false;
this.menu.classList.remove('is-open');
this.toggle.setAttribute('aria-expanded', 'false');
document.body.classList.remove('menu-open');
}
}
// Initialize
const toggle = document.querySelector('[data-mobile-menu-toggle]');
const menu = document.querySelector('[data-mobile-menu]');
if (toggle && menu) {
new MobileMenu(toggle, menu);
}
Why better:
- State managed in JavaScript, reflected in DOM
- Uses classes, not inline styles
- Proper ARIA attributes
- Testable (can instantiate MobileMenu in tests)
- Encapsulated (no global functions)
Impact: Medium effort (3 hours), high value (code quality + accessibility)
Problem 4: Complex Language Switcher
File: _layouts/default.html (lines 219-257)
Current implementation: 39 lines of manual URL mapping
function switchLanguage(lang) {
localStorage.setItem('preferredLanguage', lang);
const currentPath = window.location.pathname;
let newPath;
if (lang === 'es') {
if (!cleanPath.includes('/es/')) {
newPath = cleanPath
.replace('/work/', '/es/trabajo/')
.replace('/ai-projects/', '/es/proyectos-ia/')
.replace('/resources/', '/es/recursos/')
.replace('/contact/', '/es/contacto/');
if (newPath === cleanPath) {
newPath = '/es' + cleanPath;
}
}
} else {
newPath = cleanPath
.replace('/es/trabajo/', '/work/')
.replace('/es/proyectos-ia/', '/ai-projects/')
.replace('/es/recursos/', '/resources/')
.replace('/es/contacto/', '/contact/')
.replace('/es/', '/');
}
window.location.pathname = baseUrl + newPath;
}
Problems:
- Hardcoded paths - Add a new page? Update this function
- No single source of truth - Path mappings exist nowhere else
- Easy to break - Typo in any path breaks switching
- Not scalable - What if you add 10 more pages?
Better approach using data:
// _data/language_paths.yml
paths:
- en: /work/
es: /es/trabajo/
- en: /ai-projects/
es: /es/proyectos-ia/
- en: /resources/
es: /es/recursos/
- en: /contact/
es: /es/contacto/
// /assets/js/language-switcher.js
const PATH_MAP = {
en_to_es: {
'/work/': '/es/trabajo/',
'/ai-projects/': '/es/proyectos-ia/',
'/resources/': '/es/recursos/',
'/contact/': '/es/contacto/'
},
es_to_en: {
'/es/trabajo/': '/work/',
'/es/proyectos-ia/': '/ai-projects/',
'/es/recursos/': '/resources/',
'/es/contacto/': '/contact/'
}
};
function switchLanguage(targetLang) {
localStorage.setItem('preferredLanguage', targetLang);
const currentPath = window.location.pathname;
const map = targetLang === 'es' ? PATH_MAP.en_to_es : PATH_MAP.es_to_en;
// Try exact match first
if (map[currentPath]) {
window.location.pathname = map[currentPath];
return;
}
// Try partial match
for (const [oldPath, newPath] of Object.entries(map)) {
if (currentPath.includes(oldPath)) {
window.location.pathname = currentPath.replace(oldPath, newPath);
return;
}
}
// Fallback: toggle /es/ prefix
if (targetLang === 'es') {
window.location.pathname = '/es' + currentPath;
} else {
window.location.pathname = currentPath.replace(/^\/es/, '');
}
}
Even better: Generate this from Jekyll data:
// _includes/language-paths.js
const PATH_MAP = {
en_to_es: {
},
es_to_en: {
}
};
Why better:
- Single source of truth (language_paths.yml)
- Easy to add new pages
- Less code to maintain
- Harder to break
Impact: Medium effort (3 hours), high value (maintainability)
⚠️ PARTIALLY RESOLVED Oct 8, 2025 - Console.log in Production
File: _pages/ai-projects.html (lines 159, 176-189, 207-209) → NOW CLEAN
Resolution (Oct 8, 2025):
- ✅ Removed ALL 8 console.logs from ai-projects.html
- ✅ Extracted JavaScript modules are production-clean
- ⚠️ REMAINING: 54 console.logs in
/tools/and/docs/folders (non-production code)
~~```javascript console.log(‘Initializing AI Projects page - VERSION 2 WITH TOOLTIPS’); // … 6 more console.logs
**Status:** Production pages are now clean. Non-critical tools/docs still have debug logs.
**Original Problems (NOW FIXED for production):**
1. ~~Performance impact~~ - Eliminated from production pages
2. ~~Clutters browser console~~ - Clean console on live site
3. ~~Can leak information~~ - No info leakage in production
4. ~~Unprofessional~~ - Professional production code achieved
**Solution:** Use a debug flag:
```javascript
const DEBUG = false; // Set to true for development
function log(...args) {
if (DEBUG) {
console.log('[AI Projects]', ...args);
}
}
// Usage
log('Processing:', fullText);
Or: Remove entirely and use browser debugger when needed.
Impact: Low effort (15 minutes), medium value (professionalism)
Architecture Recommendations
1. Establish Build Process
Current: Jekyll builds SCSS, that’s it.
Recommended: Add JavaScript bundling and minification
Option A: Simple (esbuild)
npm install --save-dev esbuild
// package.json
{
"scripts": {
"js:build": "esbuild assets/js/main.js --bundle --minify --outfile=assets/js/bundle.js",
"js:watch": "esbuild assets/js/main.js --bundle --watch --outfile=assets/js/bundle.js",
"build": "npm run js:build && bundle exec jekyll build",
"dev": "npm run js:watch & bundle exec jekyll serve --livereload"
}
}
Benefits:
- Minified JavaScript
- Module support (import/export)
- Source maps for debugging
- Fast build times
Option B: Full (Webpack)
More powerful but more complex. Only if you need advanced features.
Recommendation: Start with esbuild. It’s fast and simple.
2. Testing Strategy
Current: No tests
Recommended: Add basic tests for JavaScript logic
Setup:
npm install --save-dev jest @testing-library/dom
// tests/mobile-menu.test.js
import { MobileMenu } from '../assets/js/mobile-menu.js';
describe('MobileMenu', () => {
let toggle, menu;
beforeEach(() => {
document.body.innerHTML = `
<button data-mobile-menu-toggle aria-expanded="false"></button>
<nav data-mobile-menu class="site-nav"></nav>
`;
toggle = document.querySelector('[data-mobile-menu-toggle]');
menu = document.querySelector('[data-mobile-menu]');
});
test('opens menu on click', () => {
const mobileMenu = new MobileMenu(toggle, menu);
toggle.click();
expect(menu.classList.contains('is-open')).toBe(true);
expect(toggle.getAttribute('aria-expanded')).toBe('true');
});
test('closes menu when clicking link', () => {
const mobileMenu = new MobileMenu(toggle, menu);
menu.innerHTML = '<a href="/work/">Work</a>';
toggle.click(); // Open
menu.querySelector('a').click(); // Click link
expect(menu.classList.contains('is-open')).toBe(false);
});
});
Benefits:
- Catch bugs before deployment
- Confidence when refactoring
- Documentation through tests
- Professional development practice
Recommendation: Start with tests for critical interactions (mobile menu, language switcher, project filtering).
3. Code Quality Tools
Recommended additions:
npm install --save-dev eslint prettier stylelint
ESLint config (.eslintrc.json):
{
"env": {
"browser": true,
"es2021": true
},
"extends": "eslint:recommended",
"parserOptions": {
"ecmaVersion": 12,
"sourceType": "module"
},
"rules": {
"no-console": "warn",
"no-unused-vars": "warn"
}
}
Prettier config (.prettierrc):
{
"semi": true,
"singleQuote": true,
"tabWidth": 2,
"trailingComma": "es5"
}
Stylelint config (.stylelintrc.json):
{
"extends": "stylelint-config-standard-scss",
"rules": {
"selector-class-pattern": null,
"color-hex-length": "long"
}
}
Add to package.json:
{
"scripts": {
"lint:js": "eslint assets/js/**/*.js",
"lint:css": "stylelint _sass/**/*.scss",
"lint": "npm run lint:js && npm run lint:css",
"format": "prettier --write assets/js/**/*.js _sass/**/*.scss"
}
}
Benefits:
- Consistent code style
- Catch common bugs
- Auto-formatting saves time
- Professional standard
Performance Optimizations
1. Font Loading Strategy
Current (default.html, lines 17-19):
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Crimson+Text:ital,wght@0,400;0,600;1,400&family=Inter:wght@400;500;600;700&display=swap" rel="stylesheet">
Problem: Render-blocking, requires external requests
Better approach: Self-host with font-display
- Download fonts from Google Fonts
- Add to
/assets/fonts/ - Use CSS @font-face:
// _sass/_typography.scss
@font-face {
font-family: 'Inter';
src: url('/assets/fonts/inter-var.woff2') format('woff2');
font-weight: 100 900;
font-display: swap; // Shows fallback immediately
}
@font-face {
font-family: 'Crimson Text';
src: url('/assets/fonts/crimson-text-regular.woff2') format('woff2');
font-weight: 400;
font-display: swap;
}
Benefits:
- No external requests (faster)
- Works offline
- font-display: swap prevents invisible text
- Full control over loading
Impact: ~200-400ms faster initial render
2. Image Optimization
Current: JPG/PNG files, lazy loading
Better: WebP with fallbacks, responsive images
<picture>
<source srcset="/assets/images/project-image.webp" type="image/webp">
<source srcset="/assets/images/project-image.jpg" type="image/jpeg">
<img src="/assets/images/project-image.jpg"
alt="Project screenshot"
loading="lazy"
width="800"
height="600">
</picture>
Automated conversion:
npm install --save-dev sharp
# Convert images
node scripts/convert-images.js
// scripts/convert-images.js
const sharp = require('sharp');
const fs = require('fs');
const path = require('path');
const inputDir = './assets/images';
const files = fs.readdirSync(inputDir);
files.forEach(file => {
if (file.match(/\.(jpg|png)$/)) {
const input = path.join(inputDir, file);
const output = path.join(inputDir, file.replace(/\.(jpg|png)$/, '.webp'));
sharp(input)
.webp({ quality: 80 })
.toFile(output)
.then(() => console.log(`Converted ${file} to WebP`));
}
});
Benefits:
- 30-50% smaller file sizes
- Faster page loads
- Better user experience
3. Critical CSS
Current: All CSS loads before render
Better: Inline critical CSS, defer non-critical
Extract critical CSS:
npm install --save-dev critical
// scripts/generate-critical-css.js
const critical = require('critical');
critical.generate({
inline: true,
base: '_site/',
src: 'index.html',
target: 'index-critical.html',
width: 1300,
height: 900
});
Result: Above-the-fold content styled immediately, rest loads async.
Impact: Improved First Contentful Paint (FCP)
Security Considerations
1. Content Security Policy
Add to _layouts/default.html:
<meta http-equiv="Content-Security-Policy"
content="default-src 'self';
script-src 'self' 'unsafe-inline';
style-src 'self' 'unsafe-inline' fonts.googleapis.com;
font-src 'self' fonts.gstatic.com;
img-src 'self' data: https:;
connect-src 'self';">
Adjust as needed for your external resources.
2. Form Security
If you add contact form:
<form action="..." method="POST">
<input type="hidden" name="_csrf" value="">
<!-- Form fields -->
</form>
Always validate server-side, even for static sites using form services.
3. External Links
From _layouts/default.html (line 146):
Good: You’re already using rel="noopener noreferrer" for external links.
Recommendation: Apply this to ALL external links consistently:
Code Review Checklist
Use this checklist for future code additions:
JavaScript
- No inline scripts (use external files)
- No global functions (use modules or IIFE)
- Event listeners, not onclick attributes
- No console.logs in production
- Proper error handling
- Accessible (ARIA, keyboard support)
- Mobile-tested
HTML
- Semantic elements (<nav>, <main>, <article>, etc.)
- Proper heading hierarchy (h1 → h2 → h3)
- Alt text on all images
- Form labels associated with inputs
- No duplicated IDs
- Valid HTML (use validator.w3.org)
CSS/SCSS
- Uses design system variables
- No hardcoded colors/spacing
- Mobile-first media queries
- No !important (except utilities)
- Consistent naming (BEM or similar)
- No overly specific selectors (max 3 levels)
Accessibility
- Color contrast passes WCAG AA (ideally AAA)
- Keyboard navigable
- Screen reader tested (use NVDA/JAWS)
- Focus indicators visible
- ARIA attributes where needed
- Skip links on complex pages
Performance
- Images optimized (WebP)
- Images have width/height attributes
- Lazy loading on below-fold images
- CSS minified
- JavaScript bundled and minified
- No render-blocking resources
Action Plan: Technical Improvements
Week 1: Quick Fixes (4-6 hours)
Day 1: Remove console.logs (15 min)
- Search for all console.log statements
- Remove or add DEBUG flag
Day 2: Fix mobile menu accessibility (2 hours)
- Add aria-expanded
- Add aria-controls
- Test with keyboard navigation
- Test with screen reader
Day 3: Extract project filtering JavaScript (2 hours)
- Create /assets/js/projects-filter.js
- Move filtering logic from HTML
- Update template to load new file
Day 4: Fix language switcher (2 hours)
- Create _data/language_paths.yml
- Simplify switchLanguage function
- Test all language switches
Week 2: Architecture (8-10 hours)
Day 5: Set up build process (3 hours)
- Install esbuild
- Create build scripts
- Test JavaScript bundling
- Update deployment process
Day 6: Refactor mobile navigation (3 hours)
- Remove duplicated nav markup
- Create CSS-only show/hide
- Refactor JavaScript to class-based
- Test on multiple devices
Day 7: Code quality tools (2 hours)
- Install ESLint, Prettier, Stylelint
- Configure for your preferences
- Run linters and fix issues
- Add to npm scripts
Month 1: Major Improvements (16-20 hours)
Week 3: Testing setup (6 hours)
- Install Jest
- Write tests for mobile menu
- Write tests for project filtering
- Write tests for language switcher
Week 4: Performance optimization (6 hours)
- Self-host fonts
- Convert images to WebP
- Implement responsive images
- Generate critical CSS
Week 5: Module organization (6 hours)
- Create proper JavaScript module structure
- Separate concerns (UI, state, data)
- Add JSDoc comments
- Update documentation
Success Metrics (Technical)
Code Quality
Before:
- 346 lines of inline JavaScript
- 6 console.logs in production
- No tests
- No linting
After:
- 0 lines of inline JavaScript
- 0 console.logs in production
- 80%+ test coverage on critical features
- ESLint/Prettier configured and passing
Performance
Before (estimated):
- Lighthouse: 85-90
- FCP: 1.5-2s
- LCP: 2.5-3s
After (potential):
- Lighthouse: 95-100
- FCP: < 1s
- LCP: < 2s
Maintainability
Before:
- Adding a page requires updating 3 places
- JavaScript mixed with HTML
- No tests to catch regressions
After:
- Adding a page requires updating 1 data file
- Clean separation of concerns
- Tests catch breaking changes
Final Thoughts
Your technical implementation is already good. These improvements are about going from good to excellent.
Priority ranking:
- High Impact, Low Effort: Remove console.logs, fix mobile menu accessibility
- High Impact, Medium Effort: Extract JavaScript to files, refactor navigation
- Medium Impact, Medium Effort: Set up build process, add linting
- Lower Impact, Higher Effort: Testing setup, performance optimizations
Start with #1. You’ll see immediate improvement in code professionalism.
The architecture improvements (#2-4) are investments in maintainability. They pay off when you:
- Add new features
- Fix bugs
- Collaborate with others
- Come back to the code after months
You write clean code. Now make it maintainable code, and your portfolio will be technically impressive in addition to functionally solid.