<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Oluchi Okwuosa</title>
    <description>The latest articles on DEV Community by Oluchi Okwuosa (@oluchii).</description>
    <link>https://dev.to/oluchii</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3783407%2Fb4124ecc-5c40-4457-afc1-c4702d6031c5.jpg</url>
      <title>DEV Community: Oluchi Okwuosa</title>
      <link>https://dev.to/oluchii</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/oluchii"/>
    <language>en</language>
    <item>
      <title>Wrapping Up Ekehi: The Code, The Team, and What I Am Taking With Me</title>
      <dc:creator>Oluchi Okwuosa</dc:creator>
      <pubDate>Sat, 28 Mar 2026 08:19:12 +0000</pubDate>
      <link>https://dev.to/oluchii/wrapping-up-ekehi-the-code-the-team-and-what-i-am-taking-with-me-2ofa</link>
      <guid>https://dev.to/oluchii/wrapping-up-ekehi-the-code-the-team-and-what-i-am-taking-with-me-2ofa</guid>
      <description>&lt;p&gt;Ekehi, meaning "sunrise" or "discovery", is an open-source business resource platform built for women entrepreneurs in Nigeria and across Africa. The problem it solves is real: funding exists, grants exist, credit schemes and training programmes exist, but finding them is genuinely hard, especially if you are not already connected to the right people. Ekehi puts all of that in one place. A searchable, filterable directory of funding opportunities, credit products, and training resources, built mobile-first for the women who need it most.&lt;/p&gt;

&lt;p&gt;The platform is live at &lt;a href="http://ekehi.netlify.app" rel="noopener noreferrer"&gt;ekehi.netlify.app&lt;/a&gt; and the full codebase is open source. Built by 15 people across four sprints. See it here: &lt;a href="https://github.com/Tabi-Project/Ekehi" rel="noopener noreferrer"&gt;Ekehi on GitHub&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is my final sprint entry. Four weeks, three previous articles, and a lot of lessons.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Product and Why It Exists
&lt;/h2&gt;

&lt;p&gt;Ekehi is a business intelligence platform designed to bridge the gap between women entrepreneurs and limited access to capital, professional networks, and visibility. It serves as a searchable, filterable hub that connects women-led SMEs with active grants, credit schemes, and growth training, all in one place.&lt;/p&gt;

&lt;p&gt;The stack the team was assigned to build with is Vanilla HTML, CSS, and JavaScript on the frontend with Node.js and Express.js on the backend and Supabase handling the database and authentication. For many of the women this platform serves, mobile is the primary device and connectivity is not always reliable. Every technical decision on this project sits inside that context.&lt;/p&gt;

&lt;p&gt;The choice of purple as a primary colour was intentional. By aligning with the global identity of International Women's Day, the platform signals immediate trust and dignity to the women it is built for. &lt;/p&gt;




&lt;h2&gt;
  
  
  The Journey So Far
&lt;/h2&gt;

&lt;p&gt;I published articles covering my work in each sprint. Here is the quick version:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Sprint 1&lt;/strong&gt; — Built the Mission section on the landing page. The technical challenge was positioning four decorative SVG petal icons around the eyebrow label using absolute positioning rather than flexbox, which kept them from disrupting the layout flow.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Sprint 2&lt;/strong&gt; — Built the filter section on the Opportunities page. This was the most layered task I worked on across the whole sprint. ES module imports, a shared component system, CSS scoping, JavaScript wiring, and a filter state object all in one task.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Sprint 3&lt;/strong&gt; — Refactored the What We Offer section into a two-column interactive layout with CSS Grid and JavaScript click handlers for item activation.&lt;/p&gt;

&lt;p&gt;Each of those sprints has a full write-up. This article covers Sprint 4 and wraps up the full journey.&lt;/p&gt;




&lt;h2&gt;
  
  
  What I Shipped This Week
&lt;/h2&gt;

&lt;p&gt;My final task was building the guide detail page at &lt;code&gt;client/resources/guides/detail/&lt;/code&gt;. This is the reading page that renders a single guide's full content when a user navigates from the resources page.&lt;/p&gt;




&lt;h2&gt;
  
  
  The HTML Structure
&lt;/h2&gt;

&lt;p&gt;Before writing any CSS or JavaScript, the HTML structure came first. The page has two main areas: a sidebar on the left and an article on the right. The semantic element choices were deliberate:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;main&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"container"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"guide"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;aside&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"guide__sidebar"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;a&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"/resources/"&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"guide__back"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;← Go back&lt;span class="nt"&gt;&amp;lt;/a&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;nav&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"guide__toc"&lt;/span&gt; &lt;span class="na"&gt;aria-label=&lt;/span&gt;&lt;span class="s"&gt;"Table of contents"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"toc-root"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;/nav&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/aside&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;article&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"guide__content"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;h1&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"guide__title"&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"guide-title"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/h1&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"guide__body"&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"guide-body"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/article&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/main&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;&amp;lt;aside&amp;gt;&lt;/code&gt; is the correct semantic tag for secondary content that supports the main content. &lt;code&gt;&amp;lt;nav&amp;gt;&lt;/code&gt; inside the sidebar is correct because the table of contents is navigation within the page. &lt;code&gt;&amp;lt;article&amp;gt;&lt;/code&gt; is correct for the main content because a guide is a self-contained piece of long-form content that makes sense on its own.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;id="toc-root"&lt;/code&gt; and &lt;code&gt;id="guide-body"&lt;/code&gt; divs are empty mounting points. JavaScript fills them with content at runtime.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Layout
&lt;/h2&gt;

&lt;p&gt;The two-column layout uses CSS Grid with &lt;code&gt;250px 1fr&lt;/code&gt; rather than &lt;code&gt;1fr 1fr&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nc"&gt;.guide&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;grid&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="py"&gt;grid-template-columns&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;250px&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="n"&gt;fr&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="py"&gt;gap&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;var&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;--space-16&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="py"&gt;padding-block&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;var&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;--space-10&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nl"&gt;align-items&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The sidebar has a predictable fixed width since it just holds a list of links. The content area should take all the remaining space since it holds long-form article text. Equal columns would waste space on the sidebar and squish the content. &lt;code&gt;align-items: start&lt;/code&gt; keeps the sidebar from stretching to match the full height of the article.&lt;/p&gt;

&lt;p&gt;The sidebar is sticky so it stays visible as the user scrolls through the long content without moving with the page.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Routing
&lt;/h2&gt;

&lt;p&gt;There is no API endpoint for guides yet so the page uses hardcoded dummy data. The routing reads a &lt;code&gt;guideId&lt;/code&gt; from the URL using &lt;code&gt;URLSearchParams&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;params&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;URLSearchParams&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;location&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;search&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;guideId&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;guideId&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A URL like &lt;code&gt;/resources/guides/detail/index.html?guideId=1&lt;/code&gt; gives &lt;code&gt;guideId&lt;/code&gt; the value &lt;code&gt;"1"&lt;/code&gt;. The guides object is keyed with string keys to match. If the &lt;code&gt;guideId&lt;/code&gt; is missing or does not match anything in the data, the page shows a friendly error state instead of breaking.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Collapsible Table of Contents
&lt;/h2&gt;

&lt;p&gt;The issue specifically required a collapsible table of contents. Each section heading is a button that toggles its sub-items open and closed using &lt;code&gt;aria-expanded&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;headingBtn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;click&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;isExpanded&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;headingBtn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getAttribute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;aria-expanded&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;true&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nx"&gt;headingBtn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setAttribute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;aria-expanded&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;isExpanded&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
  &lt;span class="nx"&gt;itemList&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;style&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;display&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;isExpanded&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;none&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;flex&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;aria-expanded&lt;/code&gt; tells screen readers whether the section is open or closed so keyboard and assistive technology users know the state of the TOC without having to guess.&lt;/p&gt;

&lt;p&gt;The TOC items are &lt;code&gt;&amp;lt;button&amp;gt;&lt;/code&gt; elements rather than &lt;code&gt;&amp;lt;span&amp;gt;&lt;/code&gt; elements. This came up as a PR review comment from GitHub Copilot. Spans are not keyboard focusable by default which means keyboard users could not interact with the TOC. Buttons are focusable natively and behave correctly without any extra work.&lt;/p&gt;

&lt;p&gt;The active item gets a tilde prefix through CSS alone with no extra JavaScript needed:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nc"&gt;.guide__toc-item--active&lt;/span&gt;&lt;span class="nd"&gt;::before&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;"~ "&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Responsive Behaviour
&lt;/h2&gt;

&lt;p&gt;On mobile the table of contents is hidden entirely and the layout collapses to a single column. The decision to hide rather than collapse the TOC was deliberate. On a small screen a long list of navigation links before the article content creates friction. The reader just wants to get to the content. The Go back link stays visible since it sits outside the TOC as a sibling element, not inside it.&lt;/p&gt;




&lt;h2&gt;
  
  
  Full Sprint Retrospective
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;What went well&lt;/strong&gt; was the tooling and the structure. GitHub Issues, ClickUp, and the branching strategy kept the project moving even when things got messy. Having clear acceptance criteria on every issue meant you always knew what done looked like. The team leads showing up and keeping momentum going made the difference in weeks where things could have stalled.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What surprised me&lt;/strong&gt; was how much communication, or the lack of it, can affect a whole team. People not showing up to tasks, going quiet when help is needed, and being unwilling to step outside their assigned role even when the whole team might suffer for it. That was hard to watch and harder to manage. Leadership also surprised me. It is not something you prepare for. You just have to stand up and take the lead even when others are not following, and figure it out as you go.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What I would do differently&lt;/strong&gt; is take up more responsibility earlier. I held back in some areas where I could have stepped in and I think the team would have benefited if I had been more proactive from the start. I would also push harder on communication from week one rather than trying to manage the gaps later.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What I am most proud of&lt;/strong&gt; is the filter section on the Opportunities page from Sprint 2. It was the most layered task I worked on across the whole sprint. ES module imports, a shared component system, CSS scoping, JavaScript wiring, and a filter state object all in one task. Working through a conflict between what the issue specified and what the codebase actually supported at the time, methodically rather than panicking, was a personal win for me.&lt;/p&gt;




&lt;h2&gt;
  
  
  Key Technical Lessons
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;CSS Grid vs Flexbox.&lt;/strong&gt; I went into this project knowing Flexbox but not really knowing when to reach for Grid. By the end I understood it clearly. Flexbox for one-dimensional layouts, Grid for two-dimensional ones. Every two-column layout I built across the sprint used Grid because both columns needed to be aware of each other vertically.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Working within a design system.&lt;/strong&gt; Every value traces back to a CSS custom property. No hardcoded colours or values. This discipline took getting used to but I understand now why it matters. Consistency across a codebase with 15 contributors would fall apart without it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;CSS scoping.&lt;/strong&gt; When a component renders its own HTML at runtime through JavaScript, you cannot add classes to its internal elements directly in your HTML. You scope your styles through a parent BEM class you control. This keeps your overrides contained to your section and leaves the shared component untouched everywhere else.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Semantic HTML is not optional.&lt;/strong&gt; Choosing the right HTML element matters. &lt;code&gt;&amp;lt;aside&amp;gt;&lt;/code&gt; for sidebar content, &lt;code&gt;&amp;lt;nav&amp;gt;&lt;/code&gt; for navigation lists, &lt;code&gt;&amp;lt;article&amp;gt;&lt;/code&gt; for self-contained content, &lt;code&gt;&amp;lt;button&amp;gt;&lt;/code&gt; for anything interactive. These choices affect accessibility, screen reader behaviour, and keyboard navigation.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Reading someone else's code before touching it.&lt;/strong&gt; Refactoring the What We Offer section in Sprint 3 taught me to slow down before writing anything. Read first, understand the structure, then make changes. Jumping in too quickly causes more problems than it solves.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Git as a collaboration tool.&lt;/strong&gt; Forking, upstream syncing, pull requests, merge conflicts, ES module imports. I came into this project as a beginner and the git workflow alone taught me more than I expected. One merged PR on a real open source project teaches you more than ten personal projects built alone.&lt;/p&gt;




&lt;h2&gt;
  
  
  What Is Next
&lt;/h2&gt;

&lt;p&gt;I plan to strengthen my JavaScript fundamentals properly before moving on. After that, TypeScript is the next step. I also want to start learning how to integrate data structures and algorithms into writing better, more efficient code. This sprint showed me that knowing how to write code is one thing. Writing code that is clean, scalable, and makes sense to someone else is entirely another.&lt;/p&gt;




&lt;h2&gt;
  
  
  Meet The Team
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Frontend Track&lt;/strong&gt;&lt;br&gt;
Marionbraide — &lt;a href="mailto:marionbraideinfo@gmail.com"&gt;marionbraideinfo@gmail.com&lt;/a&gt;&lt;br&gt;
Osezele Iboi — &lt;a href="mailto:ejemeniboi@gmail.com"&gt;ejemeniboi@gmail.com&lt;/a&gt;&lt;br&gt;
Esther Orieji — &lt;a href="mailto:oriejiesther@gmail.com"&gt;oriejiesther@gmail.com&lt;/a&gt;&lt;br&gt;
Iyobosa — &lt;a href="mailto:omosiyobo@gmail.com"&gt;omosiyobo@gmail.com&lt;/a&gt;&lt;br&gt;
Oluchi Okwuosa — &lt;a href="mailto:Okwuosaoluchi95@gmail.com"&gt;Okwuosaoluchi95@gmail.com&lt;/a&gt;&lt;br&gt;
Victor Okoukoni — &lt;a href="mailto:victorokoukoni@gmail.com"&gt;victorokoukoni@gmail.com&lt;/a&gt;&lt;br&gt;
Florence Onwuegbuzie — &lt;a href="mailto:florenceworkhub@gmail.com"&gt;florenceworkhub@gmail.com&lt;/a&gt;&lt;br&gt;
Fatihat — &lt;a href="mailto:fatihatulkhaer@gmail.com"&gt;fatihatulkhaer@gmail.com&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;UI/UX Track&lt;/strong&gt;&lt;br&gt;
Michael Babjide Boluwatife&lt;br&gt;
Fisayo Rotibi&lt;br&gt;
Osuji Wisdom&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Mobile Track&lt;/strong&gt;&lt;br&gt;
Gabriel Abubakar — Contributing as QA&lt;br&gt;
Jesse Nwaokolo — Contributing to frontend&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Backend Track&lt;/strong&gt;&lt;br&gt;
Olusegun Adeleke&lt;br&gt;
Sodiq Semiu&lt;/p&gt;




&lt;p&gt;&lt;em&gt;TEE Foundation | Tabi Project | International Women's Day Initiative | March 2026&lt;/em&gt;&lt;/p&gt;

</description>
      <category>opensource</category>
      <category>iwd</category>
    </item>
    <item>
      <title>Building Ekehi Sprint 3: Code, People, and the Journey So Far</title>
      <dc:creator>Oluchi Okwuosa</dc:creator>
      <pubDate>Sat, 28 Mar 2026 08:06:39 +0000</pubDate>
      <link>https://dev.to/oluchii/building-ekehi-sprint-3-code-people-and-the-journey-so-far-1mpc</link>
      <guid>https://dev.to/oluchii/building-ekehi-sprint-3-code-people-and-the-journey-so-far-1mpc</guid>
      <description>&lt;p&gt;This week my task was refactoring the What We Offer section on the Ekehi landing page. The section existed already but used a static layout. The new design called for a two-column grid with a selectable list on the left and a static contextual image on the right, with the active list item highlighted in lavender.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Task
&lt;/h2&gt;

&lt;p&gt;This week's task had me refactoring someone else's code from the team and it was a whole new experience for me, having to read and understand the person's logic and idea and also looking at the new design to figure out what needs to change and what needs to remain.&lt;/p&gt;

&lt;p&gt;The specific requirements were:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Two-column layout using CSS Grid&lt;/li&gt;
&lt;li&gt;Four selectable items: Funding Database, Training Programmes, Business Tools, Mentorship Network&lt;/li&gt;
&lt;li&gt;Active item gets a lavender highlight background&lt;/li&gt;
&lt;li&gt;JavaScript click handlers so clicking an item activates it&lt;/li&gt;
&lt;li&gt;Training Programmes selected by default on page load&lt;/li&gt;
&lt;li&gt;Right column image stays static&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Technical Decisions
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Restructuring the HTML&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The first step was getting the HTML structure right before touching any CSS. The existing markup did not follow BEM naming consistently and had unnecessary wrapper divs adding noise without purpose.&lt;/p&gt;

&lt;p&gt;The final structure uses semantic HTML throughout. A &lt;code&gt;&amp;lt;ul&amp;gt;&lt;/code&gt; with &lt;code&gt;&amp;lt;li&amp;gt;&lt;/code&gt; items for the list since they are a collection of related items. Each &lt;code&gt;&amp;lt;li&amp;gt;&lt;/code&gt; contains a &lt;code&gt;&amp;lt;div&amp;gt;&lt;/code&gt; for the card rather than &lt;code&gt;&amp;lt;article&amp;gt;&lt;/code&gt;. Article is for self-contained content that makes sense outside of its context, like a blog post. A feature item in a list does not meet that bar, so a plain div is more accurate.&lt;/p&gt;

&lt;p&gt;The BEM naming across the section:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;offerings (section)
  offerings__grid (two column wrapper)
    offerings__left (left column)
      offerings__title
      offerings__list (ul)
        offerings__item (li)
          offerings__card (div)
            offerings__card-title
            offerings__card-description
    offerings__right (right column)
      offerings__subtitle
      offerings__image
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;CSS Grid for the Two Column Layout&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The layout decision between Flexbox and CSS Grid came down to what the design needed. Flexbox handles one dimension, either a row or a column. CSS Grid handles two dimensions simultaneously. Since the two columns needed to be aware of each other vertically, Grid was the right choice.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nc"&gt;.offerings__grid&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;grid&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="py"&gt;grid-template-columns&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="n"&gt;fr&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="n"&gt;fr&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="py"&gt;gap&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;var&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;--space-10&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nl"&gt;align-items&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;stretch&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;align-items: stretch&lt;/code&gt; makes both columns the same height, which is what allowed the image to fill the full height of the right column to match the Figma design.&lt;/p&gt;

&lt;p&gt;Inside the left column, Flexbox handles the vertical stacking of the title and list since it is one dimension. This is the most common real world pattern: Grid for the macro layout, Flexbox for the micro layout inside it.&lt;/p&gt;




&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Styling the Active State&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nc"&gt;.offerings__card--active&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;background-color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;var&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;--color-purple-50&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nc"&gt;.offerings__card&lt;/span&gt;&lt;span class="nd"&gt;:hover&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;background-color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;var&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;--color-primary-subtle&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nl"&gt;cursor&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;pointer&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="py"&gt;padding-inline&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;var&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;--space-4&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No hardcoded colour values. Everything references the design system's CSS custom properties.&lt;/p&gt;




&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;JavaScript Click Handlers&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The interactivity required was straightforward. Clicking a card removes the active state from all cards and adds it to the clicked one. Training Programmes gets the active class in the HTML by default so it is highlighted on page load without JavaScript needing to do anything extra.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;cards&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;querySelectorAll&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;.offerings__card&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nx"&gt;cards&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;forEach&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;card&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;card&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;click&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;cards&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;forEach&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;classList&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;remove&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;offerings__card--active&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
    &lt;span class="nx"&gt;card&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;classList&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;offerings__card--active&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The reason &lt;code&gt;.offerings__card&lt;/code&gt; is targeted in the JS and not &lt;code&gt;.offerings__item&lt;/code&gt; is because &lt;code&gt;offerings__card--active&lt;/code&gt; is the class that controls the highlight and it lives on the div, not the li. You target what you need to add and remove the class on.&lt;/p&gt;




&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Responsive Styles&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="k"&gt;@media&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;max-width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;900px&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nc"&gt;.offerings__grid&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="py"&gt;grid-template-columns&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="n"&gt;fr&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="nc"&gt;.offerings__image&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="py"&gt;aspect-ratio&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;16&lt;/span&gt; &lt;span class="p"&gt;/&lt;/span&gt; &lt;span class="m"&gt;9&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;@media&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;max-width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;600px&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nc"&gt;.offerings__image&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="py"&gt;aspect-ratio&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;4&lt;/span&gt; &lt;span class="p"&gt;/&lt;/span&gt; &lt;span class="m"&gt;3&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;border-radius&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;var&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;--radius-2xl&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;On tablet and below, the two columns stack into a single column. The image switches from a fixed height to an aspect ratio so it scales proportionally on smaller screens.&lt;/p&gt;




&lt;h2&gt;
  
  
  Bugs Encountered
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;The image height&lt;/strong&gt; was the trickiest part. The original CSS had &lt;code&gt;aspect-ratio: 1/1&lt;/code&gt; applied to the wrong element. It was on the right column container which also holds the subtitle text, not just the image. This clipped the subtitle. Moving the aspect ratio and border radius to &lt;code&gt;.offerings__image&lt;/code&gt; directly fixed it. The final approach removed the fixed aspect ratio entirely and used a fixed height instead, letting &lt;code&gt;object-fit: cover&lt;/code&gt; handle the cropping.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;CSS variable math&lt;/strong&gt; was another small one. At one point the image height was written as:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nt"&gt;height&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nt"&gt;var&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nt"&gt;--space-10&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="err"&gt;10&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is invalid CSS. Math outside of &lt;code&gt;calc()&lt;/code&gt; does not work. The correct syntax is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nt"&gt;height&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nt"&gt;calc&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nt"&gt;var&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nt"&gt;--space-10&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="err"&gt;10&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or just a plain pixel value. Small syntax mistake that was pretty easy to miss.&lt;/p&gt;




&lt;h2&gt;
  
  
  Reflections
&lt;/h2&gt;

&lt;p&gt;This is the first group project I have ever worked on and that alone made&lt;br&gt;
it a different experience from anything I had done before.&lt;/p&gt;

&lt;p&gt;Using GitHub Issues made task assignment straightforward. Every task had a&lt;br&gt;
clear description, acceptance criteria, and an assignee. You knew exactly&lt;br&gt;
what you were supposed to build and what done looked like. That structure&lt;br&gt;
made it easy to pick up work and stay focused.&lt;/p&gt;

&lt;p&gt;ClickUp was completely new to me. Setting it up, configuring the custom&lt;br&gt;
fields, managing the board day to day, and keeping it updated across a team&lt;br&gt;
of 15 people was a skill I picked up entirely on this project. I did not&lt;br&gt;
expect project management tooling to be something I would learn here but it&lt;br&gt;
turned out to be one of the more valuable things I walked away with.&lt;/p&gt;

&lt;p&gt;Working as the People Manager gave me a different kind of insight. Managing&lt;br&gt;
people is genuinely hard, especially when communication breaks down. When&lt;br&gt;
team members do not turn in their tasks or go quiet, it does not just affect&lt;br&gt;
their own work, it creates more workload for everyone waiting on them&lt;br&gt;
downstream. That lesson about communication and accountability is one I will&lt;br&gt;
carry into every team I work with going forward.&lt;/p&gt;

&lt;p&gt;On the technical side, coming into this project as a beginner and working&lt;br&gt;
through forking, upstream syncing, pull requests, merge conflicts, and ES&lt;br&gt;
module imports across three sprints was a real growth arc. The git workflow&lt;br&gt;
alone taught me more than I expected. Working within a design system with&lt;br&gt;
defined CSS variables and utility classes was also new. Writing styles that&lt;br&gt;
trace back to a single source of truth rather than hardcoding values&lt;br&gt;
everywhere is a discipline that will transfer to any professional project.&lt;/p&gt;

&lt;p&gt;What worked well was the tooling and the cooperation when it was there.&lt;br&gt;
GitHub Issues, ClickUp, and the branching strategy kept the project&lt;br&gt;
structured even when things got messy. The team leads showing up and keeping&lt;br&gt;
things moving made the difference in the sprints where momentum could have&lt;br&gt;
stalled.&lt;/p&gt;

&lt;p&gt;If I could do anything differently, honestly nothing. Every part of this&lt;br&gt;
was a learning experience I am grateful for. I got to try things I had never&lt;br&gt;
done before, sharpened my communication, took on responsibility, and shipped&lt;br&gt;
real work on a real project. That is what I came for.&lt;/p&gt;

&lt;h2&gt;
  
  
  Meet The Team
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Frontend Track&lt;/strong&gt;:&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Marionbraide — &lt;a href="mailto:marionbraideinfo@gmail.com"&gt;marionbraideinfo@gmail.com&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Osezele Iboi — &lt;a href="mailto:ejemeniboi@gmail.com"&gt;ejemeniboi@gmail.com&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Esther Orieji — &lt;a href="mailto:oriejiesther@gmail.com"&gt;oriejiesther@gmail.com&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Iyobosa — &lt;a href="mailto:omosiyobo@gmail.com"&gt;omosiyobo@gmail.com&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Oluchi Okwuosa — &lt;a href="mailto:Okwuosaoluchi95@gmail.com"&gt;Okwuosaoluchi95@gmail.com&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Victor Okoukoni — &lt;a href="mailto:victorokoukoni@gmail.com"&gt;victorokoukoni@gmail.com&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Florence Onwuegbuzie — &lt;a href="mailto:florenceworkhub@gmail.com"&gt;florenceworkhub@gmail.com&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Fatihat - &lt;a class="mentioned-user" href="https://dev.to/khaerie"&gt;@khaerie&lt;/a&gt; &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;UI/UX Track:&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Michael Babjide Boluwatife&lt;/p&gt;

&lt;p&gt;Fisayo Rotibi&lt;/p&gt;

&lt;p&gt;Osuji Wisdom&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Mobile Track:&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Gabriel Abubakar — Contributing as QA&lt;/p&gt;

&lt;p&gt;Jesse Nwaokolo — Contributing to frontend&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Backend Track:&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Olusegun Adeleke&lt;/p&gt;

&lt;p&gt;Sodiq Semiu&lt;/p&gt;

&lt;p&gt;&lt;em&gt;TEE Foundation | Tabi Project | International Women's Day Initiative | March 2026&lt;/em&gt;&lt;/p&gt;

</description>
      <category>css</category>
      <category>devjournal</category>
      <category>frontend</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Building Ekehi Sprint 3: Code, People, and the Journey So Far</title>
      <dc:creator>Oluchi Okwuosa</dc:creator>
      <pubDate>Fri, 20 Mar 2026 06:55:10 +0000</pubDate>
      <link>https://dev.to/oluchii/building-ekehi-sprint-3-code-people-and-the-journey-so-far-4ean</link>
      <guid>https://dev.to/oluchii/building-ekehi-sprint-3-code-people-and-the-journey-so-far-4ean</guid>
      <description>&lt;p&gt;This week my task was refactoring the What We Offer section on the Ekehi landing page. The section existed already but used a static layout. The new design called for a two-column grid with a selectable list on the left and a static contextual image on the right, with the active list item highlighted in lavender.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Task
&lt;/h2&gt;

&lt;p&gt;This week's task had me refactoring someone else's code from the team and it was a whole new experience for me, having to read and understand the person's logic and idea and also looking at the new design to figure out what needs to change and what needs to remain.&lt;/p&gt;

&lt;p&gt;The specific requirements were:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Two-column layout using CSS Grid&lt;/li&gt;
&lt;li&gt;Four selectable items: Funding Database, Training Programmes, Business Tools, Mentorship Network&lt;/li&gt;
&lt;li&gt;Active item gets a lavender highlight background&lt;/li&gt;
&lt;li&gt;JavaScript click handlers so clicking an item activates it&lt;/li&gt;
&lt;li&gt;Training Programmes selected by default on page load&lt;/li&gt;
&lt;li&gt;Right column image stays static&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Technical Decisions
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Restructuring the HTML&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The first step was getting the HTML structure right before touching any CSS. The existing markup did not follow BEM naming consistently and had unnecessary wrapper divs adding noise without purpose.&lt;/p&gt;

&lt;p&gt;The final structure uses semantic HTML throughout. A &lt;code&gt;&amp;lt;ul&amp;gt;&lt;/code&gt; with &lt;code&gt;&amp;lt;li&amp;gt;&lt;/code&gt; items for the list since they are a collection of related items. Each &lt;code&gt;&amp;lt;li&amp;gt;&lt;/code&gt; contains a &lt;code&gt;&amp;lt;div&amp;gt;&lt;/code&gt; for the card rather than &lt;code&gt;&amp;lt;article&amp;gt;&lt;/code&gt;. Article is for self-contained content that makes sense outside of its context, like a blog post. A feature item in a list does not meet that bar, so a plain div is more accurate.&lt;/p&gt;

&lt;p&gt;The BEM naming across the section:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;offerings (section)
  offerings__grid (two column wrapper)
    offerings__left (left column)
      offerings__title
      offerings__list (ul)
        offerings__item (li)
          offerings__card (div)
            offerings__card-title
            offerings__card-description
    offerings__right (right column)
      offerings__subtitle
      offerings__image
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;CSS Grid for the Two Column Layout&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The layout decision between Flexbox and CSS Grid came down to what the design needed. Flexbox handles one dimension, either a row or a column. CSS Grid handles two dimensions simultaneously. Since the two columns needed to be aware of each other vertically, Grid was the right choice.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nc"&gt;.offerings__grid&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;grid&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="py"&gt;grid-template-columns&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="n"&gt;fr&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="n"&gt;fr&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="py"&gt;gap&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;var&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;--space-10&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nl"&gt;align-items&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;stretch&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;align-items: stretch&lt;/code&gt; makes both columns the same height, which is what allowed the image to fill the full height of the right column to match the Figma design.&lt;/p&gt;

&lt;p&gt;Inside the left column, Flexbox handles the vertical stacking of the title and list since it is one dimension. This is the most common real world pattern: Grid for the macro layout, Flexbox for the micro layout inside it.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Styling the Active State&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nc"&gt;.offerings__card--active&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;background-color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;var&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;--color-purple-50&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nc"&gt;.offerings__card&lt;/span&gt;&lt;span class="nd"&gt;:hover&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;background-color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;var&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;--color-primary-subtle&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nl"&gt;cursor&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;pointer&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="py"&gt;padding-inline&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;var&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;--space-4&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No hardcoded colour values. Everything references the design system's CSS custom properties.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;JavaScript Click Handlers&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The interactivity required was straightforward. Clicking a card removes the active state from all cards and adds it to the clicked one. Training Programmes gets the active class in the HTML by default so it is highlighted on page load without JavaScript needing to do anything extra.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;cards&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;querySelectorAll&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;.offerings__card&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nx"&gt;cards&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;forEach&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;card&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;card&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;click&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;cards&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;forEach&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;classList&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;remove&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;offerings__card--active&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
    &lt;span class="nx"&gt;card&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;classList&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;offerings__card--active&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The reason &lt;code&gt;.offerings__card&lt;/code&gt; is targeted in the JS and not &lt;code&gt;.offerings__item&lt;/code&gt; is because &lt;code&gt;offerings__card--active&lt;/code&gt; is the class that controls the highlight and it lives on the div, not the li. You target what you need to add and remove the class on.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Responsive Styles&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="k"&gt;@media&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;max-width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;900px&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nc"&gt;.offerings__grid&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="py"&gt;grid-template-columns&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="n"&gt;fr&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="nc"&gt;.offerings__image&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="py"&gt;aspect-ratio&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;16&lt;/span&gt; &lt;span class="p"&gt;/&lt;/span&gt; &lt;span class="m"&gt;9&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;@media&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;max-width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;600px&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nc"&gt;.offerings__image&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="py"&gt;aspect-ratio&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;4&lt;/span&gt; &lt;span class="p"&gt;/&lt;/span&gt; &lt;span class="m"&gt;3&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;border-radius&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;var&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;--radius-2xl&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;On tablet and below, the two columns stack into a single column. The image switches from a fixed height to an aspect ratio so it scales proportionally on smaller screens.&lt;/p&gt;




&lt;h2&gt;
  
  
  Bugs Encountered
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;The image height&lt;/strong&gt; was the trickiest part. The original CSS had &lt;code&gt;aspect-ratio: 1/1&lt;/code&gt; applied to the wrong element. It was on the right column container which also holds the subtitle text, not just the image. This clipped the subtitle. Moving the aspect ratio and border radius to &lt;code&gt;.offerings__image&lt;/code&gt; directly fixed it. The final approach removed the fixed aspect ratio entirely and used a fixed height instead, letting &lt;code&gt;object-fit: cover&lt;/code&gt; handle the cropping.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;CSS variable math&lt;/strong&gt; was another small one. At one point the image height was written as:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nt"&gt;height&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nt"&gt;var&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nt"&gt;--space-10&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="err"&gt;10&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is invalid CSS. Math outside of &lt;code&gt;calc()&lt;/code&gt; does not work. The correct syntax is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nt"&gt;height&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nt"&gt;calc&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nt"&gt;var&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nt"&gt;--space-10&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="err"&gt;10&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or just a plain pixel value. Small syntax mistake that was pretty easy to miss.&lt;/p&gt;




&lt;h2&gt;
  
  
  Reflections
&lt;/h2&gt;

&lt;p&gt;This is the first group project I have ever worked on and that alone made&lt;br&gt;
it a different experience from anything I had done before.&lt;/p&gt;

&lt;p&gt;Using GitHub Issues made task assignment straightforward. Every task had a&lt;br&gt;
clear description, acceptance criteria, and an assignee. You knew exactly&lt;br&gt;
what you were supposed to build and what done looked like. That structure&lt;br&gt;
made it easy to pick up work and stay focused.&lt;/p&gt;

&lt;p&gt;ClickUp was completely new to me. Setting it up, configuring the custom&lt;br&gt;
fields, managing the board day to day, and keeping it updated across a team of 15 people was a skill I picked up entirely on this project. I did not expect project management tooling to be something I would learn here but it turned out to be one of the more valuable things I walked away with.&lt;/p&gt;

&lt;p&gt;Working as the People Manager gave me a different kind of insight. Managing people is genuinely hard, especially when communication breaks down. When team members do not turn in their tasks or go quiet, it does not just affect their own work, it creates more workload for everyone waiting on them downstream. That lesson about communication and accountability is one I will carry into every team I work with going forward.&lt;/p&gt;

&lt;p&gt;On the technical side, coming into this project as a beginner and working&lt;br&gt;
through forking, upstream syncing, pull requests, merge conflicts, and ES&lt;br&gt;
module imports across three sprints was a real growth arc. The git workflow alone taught me more than I expected. Working within a design system with defined CSS variables and utility classes was also new. Writing styles that trace back to a single source of truth rather than hardcoding values everywhere is a discipline that will transfer to any professional project.&lt;/p&gt;

&lt;p&gt;What worked well was the tooling and the cooperation when it was there.&lt;br&gt;
GitHub Issues, ClickUp, and the branching strategy kept the project&lt;br&gt;
structured even when things got messy. The team leads showing up and keeping&lt;br&gt;
things moving made the difference in the sprints where momentum could have&lt;br&gt;
stalled.&lt;/p&gt;

&lt;p&gt;What I am most proud of shipping is the filter section on the Opportunities page from Sprint 2. It was the most layered task I worked on. ES module imports, a shared component system, CSS scoping, JavaScript wiring, and a filter state object all in one task. I also had to navigate a conflict between what the issue specified and what the codebase actually supported at the time, and working through that methodically rather than panicking was a personal win for me.&lt;/p&gt;

&lt;p&gt;If I could do anything differently, honestly nothing. Every part of this&lt;br&gt;
was a learning experience I am grateful for. I got to try things I had never done before, sharpened my communication, took on responsibility, and shipped real work on a real project. That is what I came for.&lt;/p&gt;

&lt;p&gt;Built by 15 people across three sprints. See it here: &lt;a href="https://github.com/Tabi-Project/Ekehi" rel="noopener noreferrer"&gt;Ekehi on GitHub&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Meet The Team
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Frontend Track&lt;/strong&gt;:&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Marionbraide — &lt;a href="mailto:marionbraideinfo@gmail.com"&gt;marionbraideinfo@gmail.com&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Osezele Iboi — &lt;a href="mailto:ejemeniboi@gmail.com"&gt;ejemeniboi@gmail.com&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Esther Orieji — &lt;a href="mailto:oriejiesther@gmail.com"&gt;oriejiesther@gmail.com&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Iyobosa — &lt;a href="mailto:omosiyobo@gmail.com"&gt;omosiyobo@gmail.com&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Oluchi Okwuosa — &lt;a href="mailto:Okwuosaoluchi95@gmail.com"&gt;Okwuosaoluchi95@gmail.com&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Victor Okoukoni — &lt;a href="mailto:victorokoukoni@gmail.com"&gt;victorokoukoni@gmail.com&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Florence Onwuegbuzie — &lt;a href="mailto:florenceworkhub@gmail.com"&gt;florenceworkhub@gmail.com&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Fatihat - &lt;a href="mailto:fatihatulkhaer@gmail.com"&gt;fatihatulkhaer@gmail.com&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;UI/UX Track:&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Michael Babjide Boluwatife&lt;/p&gt;

&lt;p&gt;Fisayo Rotibi&lt;/p&gt;

&lt;p&gt;Osuji Wisdom&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Mobile Track:&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Gabriel Abubakar — Contributing as QA&lt;/p&gt;

&lt;p&gt;Jesse Nwaokolo — Contributing to frontend&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Backend Track:&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Olusegun Adeleke&lt;/p&gt;

&lt;p&gt;Sodiq Semiu&lt;/p&gt;

&lt;p&gt;&lt;em&gt;TEE Foundation | Tabi Project | International Women's Day Initiative | March 2026&lt;/em&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Building Ekehi: A Contributor's Journal From Code to Coordination</title>
      <dc:creator>Oluchi Okwuosa</dc:creator>
      <pubDate>Sat, 07 Mar 2026 09:41:02 +0000</pubDate>
      <link>https://dev.to/oluchii/sprint-1-on-ekehi-building-the-foundation-and-managing-the-team-22hj</link>
      <guid>https://dev.to/oluchii/sprint-1-on-ekehi-building-the-foundation-and-managing-the-team-22hj</guid>
      <description>&lt;p&gt;Ekehi is a business resource platform for women entrepreneurs in Nigeria and across Africa. The problem it solves is real: funding exists, grants exist, credit schemes and training programmes exist, but finding them is genuinely hard, especially if you are not already connected to the right people. Ekehi puts all of that in one place. A searchable, filterable directory of funding opportunities, credit products, and training resources, built mobile-first.&lt;/p&gt;

&lt;p&gt;We are a team of 15 people. We have a Product Lead, Engineering Lead, Design Lead, Lead Maintainer, and a Backend Lead. My role on this project is People Manager, handling workflows, team synergy, and making sure nothing falls through the cracks.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Stack
&lt;/h2&gt;

&lt;p&gt;Ekehi is built on Vanilla HTML, CSS, and JavaScript on the frontend, with&lt;br&gt;
Node.js and Express.js on the backend and Supabase handling the database&lt;br&gt;
and authentication. Supabase's built-in full-text search is particularly&lt;br&gt;
relevant for a funding directory where users need to search and filter across&lt;br&gt;
dozens of opportunities quickly. The design system uses DM Serif Text for&lt;br&gt;
headings and Urbanist for body text. This was the stack we were assigned to build with.&lt;br&gt;
For many of the women this platform serves, mobile is the primary device&lt;br&gt;
and connectivity is not always reliable. Every technical decision on this&lt;br&gt;
project sits inside that context.&lt;/p&gt;

&lt;p&gt;For contributors, the project uses a tiered branching strategy:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;main&lt;/code&gt; for stable production code&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;development&lt;/code&gt; as the integration branch where features come together
before going live&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;feature/&lt;/code&gt; branches for isolated work&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Every contributor works on a feature branch, opens a pull request into&lt;br&gt;
&lt;code&gt;development&lt;/code&gt;, and waits for review before anything merges. Understanding&lt;br&gt;
this flow early saved me from several mistakes.&lt;/p&gt;


&lt;h2&gt;
  
  
  Design
&lt;/h2&gt;

&lt;p&gt;Before any frontend work began, the design team produced high fidelity screens on Figma covering all the key pages and components. Frontend development was tied directly to those designs, which meant every section had a reference to build from. &lt;br&gt;
Spacing, typography, colour, and layout decisions were all specified in the Figma file and the design system. As a frontend contributor, my job was to match what was designed as closely as possible, not to make&lt;/p&gt;
&lt;h2&gt;
  
  
  visual decisions independently.
&lt;/h2&gt;
&lt;h2&gt;
  
  
  Sprint 1
&lt;/h2&gt;

&lt;p&gt;Sprint 1 is the foundation sprint. The team was running two things in parallel: the infrastructure work that the entire product depends on, and shipping a responsive landing page as the visible deliverable for this sprint. So while the DB schema, Supabase setup, authentication, and sector taxonomy were being handled in the background, there was already something users could land on by the end of the sprint.&lt;/p&gt;

&lt;p&gt;My frontend task was the Mission section of the landing page. The section required a centred layout with a small eyebrow label, decorative SVG petal icons positioned around the text, and a large headline, all matching a Figma design.&lt;/p&gt;

&lt;p&gt;The technical challenge was the petal positioning. My first instinct was to put the SVG images inside a flex container alongside the text, but that made them sit too close to the text and resize awkwardly at different screen sizes. The fix was absolute positioning. By setting the eyebrow container to &lt;code&gt;position: relative&lt;/code&gt; and positioning each petal with &lt;code&gt;position: absolute&lt;/code&gt;, the petals float independently around the text without disrupting the layout flow. Each petal got its own class following BEM naming with &lt;code&gt;top&lt;/code&gt;, &lt;code&gt;bottom&lt;/code&gt;, &lt;code&gt;left&lt;/code&gt;, and &lt;code&gt;right&lt;/code&gt; values tuned to match the Figma design.&lt;/p&gt;

&lt;p&gt;The project uses a utility class system similar to Tailwind for common styling, with component-specific CSS files handling anything the utilities do not cover. Styling the mission section meant using utility classes in the HTML for layout and typography, then writing targeted CSS using the project's design tokens for anything specific to the component. No hardcoded pixel values or colour codes, everything traces back to CSS custom properties defined in the design system.&lt;/p&gt;


&lt;h2&gt;
  
  
  Sprint 2
&lt;/h2&gt;

&lt;p&gt;My task this sprint was building the filter section of the Opportunities page. This included the page header, a search bar, and five filter dropdowns which are Sector, Status, Business stage, Region, and Type, wired up so that every interaction logs the current filter state to the console. No API re-fetching yet as that is a separate issue. The goal was to establish the filter state object as a foundation for the upcoming API wiring.&lt;/p&gt;

&lt;p&gt;The implementation used two shared components, &lt;code&gt;SearchBar.create()&lt;/code&gt; and &lt;code&gt;Dropdown.create()&lt;/code&gt;, that the team had already built. Each dropdown receives a label, an options array with exact API enum strings as values, and an &lt;code&gt;onChange&lt;/code&gt; callback that updates a central &lt;code&gt;filters&lt;/code&gt; object and logs it. The &lt;code&gt;filters&lt;/code&gt; object lives at module scope so it will be accessible when the API wiring issue comes next.&lt;/p&gt;

&lt;p&gt;The issue specified ES module imports rather than global script tags. This meant replacing multiple &lt;code&gt;&amp;lt;script&amp;gt;&lt;/code&gt; tags in the HTML with a single &lt;code&gt;&amp;lt;script type="module" src="opportunities.js"&amp;gt;&lt;/code&gt; and importing all dependencies at the top of the JS file. The shared components needed &lt;code&gt;export default&lt;/code&gt; added to them before this worked, a small change with a meaningful impact on how the codebase scales.&lt;/p&gt;

&lt;p&gt;Styling the filter section introduced another challenge. The &lt;code&gt;Dropdown&lt;/code&gt; component renders its own HTML at runtime through JavaScript, which means you cannot add classes to its internal elements directly in your HTML. The fix was CSS scoping, targeting the component's internal class names through a parent BEM class I controlled:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nc"&gt;.opportunities__dropdowns&lt;/span&gt; &lt;span class="nc"&gt;.dropdown-wrapper&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;flex&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;flex&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nc"&gt;.opportunities__dropdowns&lt;/span&gt; &lt;span class="nc"&gt;.dropdown__trigger&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;100%&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;font-weight&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;var&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;--font-regular&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This overrides the component's default styles only within the filter section, leaving every other dropdown on the platform untouched.&lt;/p&gt;




&lt;h2&gt;
  
  
  My Role as People Manager
&lt;/h2&gt;

&lt;p&gt;Outside of contributing code, I handled the coordination and tooling setup for the team.&lt;/p&gt;

&lt;p&gt;I set up our ClickUp workspace. That meant building out the Ekehi Space, creating folders for each sprint, and configuring all the custom fields: priority levels, effort sizing, MoSCoW categories, status dropdowns, owner fields, due dates. I set up the views the team actually uses day to day. Board view for a quick status snapshot, Workload view to check capacity across the team, and filtered List view to pull up blocked items fast.&lt;/p&gt;

&lt;p&gt;I sat in on meetings across the different tracks, frontend, backend, and&lt;br&gt;
design, to stay across what each team was working on and where things stood. Beyond the meetings, I was also doing direct check-ins with individuals to follow up on assigned tasks.&lt;/p&gt;

&lt;p&gt;Our ClickUp workspace is shared across multiple teams in the organisation so everything I configured had to be scoped specifically to our Space. That required ensuring I get it right without affecting anyone else's setup.&lt;/p&gt;

&lt;p&gt;Beyond the initial setup, the day to day management of ClickUp was also on me. That means making sure tasks are actually being updated, statuses reflect what is really happening, and owners are assigned to everything that needs one. A ClickUp board that nobody updates is useless so part of my job was consistently following up with the team to keep it current.&lt;/p&gt;

&lt;p&gt;I was also filtering by blocked tasks regularly. Anything sitting on blocked for too long gets a follow up from me. Either something needs to be escalated, a decision needs to be made, or someone needs help and has not said so yet. That filter became one of the most useful things in the whole setup because it tells you exactly where the friction is without having to go through every single task manually.&lt;/p&gt;

&lt;p&gt;Working with my project lead throughout the sprint meant a lot of back and forth on task progress, making sure what was logged in ClickUp matched what was actually happening and flagging anything that looked like it was falling behind before it became a real problem.&lt;/p&gt;




&lt;h2&gt;
  
  
  Lessons Learnt
&lt;/h2&gt;

&lt;p&gt;Merge conflicts are not a crisis. They are just two sets of changes that need a decision. Understanding what each side of the conflict contains makes resolving them straightforward. The harder lesson was learning to check in with the team lead before touching shared files because a one-line addition to a shared component has implications across the whole codebase.&lt;/p&gt;

&lt;p&gt;CSS scoping matters more than it seems when working in a shared component system. Writing styles that are too broad breaks things in places you are not looking. Writing styles scoped to your own classes keeps your work contained and reviewable.&lt;/p&gt;

&lt;p&gt;Working with a team of 15 people across different functions taught me fast that collaboration only works when everyone is actually showing up for their part. When people do not turn in their tasks as at when due, it does not just affect their own work, it affects whoever is waiting on them downstream.&lt;/p&gt;

&lt;p&gt;Be specific when you need something from someone. A vague request sits in someone's inbox for days. A message that says exactly what to open, what to click, and that it will take two minutes gets done the same day.&lt;/p&gt;

&lt;p&gt;And last one: the people manager role has real work in it even during a sprint where there is nothing to demo. Keeping the team unblocked, tracking what is at risk, making sure decisions happen when they need to. That is what makes the sprints after Sprint 1 possible.&lt;/p&gt;

&lt;p&gt;Big respect to everyone on the Ekehi team, all 15 of us. Especially our Product Lead, Engineering Lead, Design Lead, Lead Maintainer, and Backend Lead for keeping things moving. It has been a solid sprint and we are just getting started.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;TEE Foundation | Tabi Project | International Women's Day Initiative | March 2026&lt;/em&gt;&lt;/p&gt;




</description>
      <category>buildinpublic</category>
      <category>devjournal</category>
      <category>management</category>
    </item>
    <item>
      <title>Building LovedIn: A Case Study</title>
      <dc:creator>Oluchi Okwuosa</dc:creator>
      <pubDate>Sat, 21 Feb 2026 08:37:57 +0000</pubDate>
      <link>https://dev.to/oluchii/building-lovedin-a-case-study-25lk</link>
      <guid>https://dev.to/oluchii/building-lovedin-a-case-study-25lk</guid>
      <description>&lt;h2&gt;
  
  
  The Problem
&lt;/h2&gt;

&lt;p&gt;Creating a platform for personalized proposals sounds straightforward until you realize what's actually at stake. It's not just a website. It's a moment. Someone's asking the most vulnerable question they can ask another person. They deserve more than a generic form. They deserve something that feels like it understands the weight of what they're doing.&lt;/p&gt;

&lt;p&gt;The project needed multiple pieces working together seamlessly. A landing page that explains what LovedIn is and gets people excited about it. A stories page where people can share their proposals and celebrate with others. And then the proposal page itself, where the magic happens.&lt;/p&gt;

&lt;p&gt;Who's going to use this? People aged 18 to 35 who want their proposals to be memorable. They're on their phones, they're probably nervous, and they want something that works smoothly without any hiccups.&lt;/p&gt;

&lt;p&gt;The goal was simple but ambitious: create a complete platform that feels personal, that celebrates what's actually happening. Not generic or boring. Something that makes you feel the weight of the moment while also making it feel safe enough to be playful about it. A platform where someone could create a customized proposal experience and then share it with the person they love.&lt;/p&gt;

&lt;h2&gt;
  
  
  How I Approached It
&lt;/h2&gt;

&lt;p&gt;I worked on three main parts of this project: the proposal page, the login page, and the signup page. Each one had its own challenge, but they all had to feel like they came from the same place, the same design language.&lt;/p&gt;

&lt;p&gt;For the proposal page, I designed it to have two distinct states visually. First, there's the question state where you see the personalized proposal. Then there's the success state that celebrates the "yes" moment. Both are built with HTML and CSS, structured so they can be toggled with a class when JavaScript gets added later. The structure made sense because it keeps everything on one page. The visual hierarchy and layout shift from one state to another through CSS class management. It's designed to be clean and cohesive.&lt;/p&gt;

&lt;p&gt;I added animated GIFs to break up the formality and set the emotional tone. The proposal state shows a cute animated character peeking out nervously, like someone getting ready to ask the big question. It's the feeling before you ask. The success state shows a baby cheering, celebrating the "yes". These aren't just random images thrown in. They set the tone. They make it feel like the page understands that this is emotional, vulnerable, and deserves celebration.&lt;/p&gt;

&lt;p&gt;The GIFs are styled to be prominent but not overwhelming. They're centered, have a border in the accent color, and cast a subtle shadow. They draw your eye but they don't scream for attention.&lt;/p&gt;

&lt;p&gt;I also designed the "No" button to do something playful. When you hover over it, it moves away. This is intentional. It's playful. It acknowledges the nervousness of the moment but keeps things light. The button doesn't disappear completely, it just shifts position. On desktop, it moves more dramatically, 80 pixels to the right and 30 pixels up. On mobile, it moves less because the screen is smaller and you don't want the button flying off screen entirely. It's 40 pixels right and 15 pixels up on smaller devices.&lt;/p&gt;

&lt;p&gt;This movement is pure CSS using transform and transition. No JavaScript needed. The transform property moves the button without affecting the layout, which keeps everything smooth and performant. The transition makes it feel responsive and snappy.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnk4vnxpzpvaxidgon4zc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnk4vnxpzpvaxidgon4zc.png" alt=" " width="800" height="375"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For the login and signup pages, the approach was different but connected.  I structured them with proper semantic HTML so they were accessible, then styled them to feel warm and inviting using the same design system. The forms had to be straightforward but not sterile. A person coming to log in or sign up is already taking a step toward something, so the interface should meet them with ease, not friction.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzg7pa6agauyhj9jfuyhx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzg7pa6agauyhj9jfuyhx.png" alt=" " width="800" height="380"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6vl8ndqt8bk94o66ksf7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6vl8ndqt8bk94o66ksf7.png" alt=" " width="800" height="378"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Both the proposal page and the auth pages had to work together in the same design language. That's where the design system became crucial.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Design System
&lt;/h2&gt;

&lt;p&gt;Colors matter more than people think, especially when you're trying to create an emotional experience. I worked with five specific colors from our design system, and each one has a purpose and a name.&lt;/p&gt;

&lt;p&gt;Scarlet Blush is #E22B3B, the primary color. It's bold, it's romantic, and it demands attention. You see it in headings and main buttons. It's confident without being aggressive. Wild Strawberry is #ED4779, the secondary color. It's softer than Scarlet Blush, more playful. It shows up in gradients and accents. It's romantic without being too serious. Petal Frost is #FA88BB, the accent color. It's tender and warm. It shows up in borders and highlights, adding softness to hard edges. Pink Carnation is #F0D1D7, the background color. It's this soft pink that makes every page feel intimate and calm. And Blush Rose is #D86A77, the support color. It grounds everything. It works for secondary text and borders, keeping things from floating away.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fytshgqyhrxrh632kgcn5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fytshgqyhrxrh632kgcn5.png" alt=" " width="800" height="218"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For fonts, I used Playfair Display for headlines. It's elegant, it's got personality, and when you see your partner's name in this font, it feels formal and important. That's intentional. Inter is what everything else uses because it's clean and readable everywhere, on every device.&lt;/p&gt;

&lt;p&gt;The whole design system exists in base.css as CSS variables. This means we're not hardcoding colors. If we ever need to change Scarlet Blush, we change it once and it updates everywhere. That's the power of a good system. My partner built this foundation, and it made everything else possible.&lt;/p&gt;

&lt;h2&gt;
  
  
  The HTML Structure
&lt;/h2&gt;

&lt;p&gt;I made sure the HTML was semantic and accessible because honestly, if people can't access your page or search engines can't understand it, none of the styling matters.&lt;/p&gt;

&lt;p&gt;For the proposal page, the structure is straightforward. There's a main section that holds two states: the proposal state and the success state. Both are built in HTML, ready for JavaScript to toggle between them. The proposal state has the question, the GIFs, and the buttons. The success state has the celebration message.&lt;/p&gt;

&lt;p&gt;For the auth pages, the structure had to be clean but also make sense. Each form is wrapped in a fieldset with a legend. The legend tells you what section you're in. The form groups are organized vertically, each with a label and input. It's simple, but it's built correctly.&lt;/p&gt;

&lt;p&gt;Each heading gets its proper semantic tag. The main question on the proposal page is an h1, the success message is an h2. This creates a proper document outline so screen readers understand what's happening.  The buttons have proper IDs so they can be targeted later with JavaScript.&lt;/p&gt;

&lt;p&gt;Here's what the proposal page structure looks like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;body&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;main&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;section&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"proposal-page active"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"back-btn"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;← Back&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;

      &lt;span class="nt"&gt;&amp;lt;section&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"proposal-container"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"proposal-state"&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"proposalState"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="nt"&gt;&amp;lt;img&lt;/span&gt; &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"..."&lt;/span&gt; &lt;span class="na"&gt;alt=&lt;/span&gt;&lt;span class="s"&gt;"Cute animated character peeking out nervously"&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"proposal-gif"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
          &lt;span class="nt"&gt;&amp;lt;h1&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"proposal-container__title"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Will you be my girlfriend?&lt;span class="nt"&gt;&amp;lt;/h1&amp;gt;&lt;/span&gt;
          &lt;span class="nt"&gt;&amp;lt;p&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"proposal-container__text"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;This is the moment that changes everything...&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;

          &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"proposal-buttons"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"proposal-buttons__yes"&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"yesBtn"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Yes! 💕&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"proposal-buttons__no"&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"noBtn"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;No!&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
          &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;

        &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"success-state"&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"successState"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="nt"&gt;&amp;lt;img&lt;/span&gt; &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"..."&lt;/span&gt; &lt;span class="na"&gt;alt=&lt;/span&gt;&lt;span class="s"&gt;"Animated baby raising their arms and cheering"&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"success-gif"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
          &lt;span class="nt"&gt;&amp;lt;h2&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"proposal-container__heading"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;You've Made Me The Happiest&lt;span class="nt"&gt;&amp;lt;/h2&amp;gt;&lt;/span&gt;
          &lt;span class="nt"&gt;&amp;lt;p&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"proposal-container__text"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Welcome to the next chapter of our story together&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
          &lt;span class="nt"&gt;&amp;lt;p&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"success-message"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;This moment, this "yes" - I'll treasure it forever...&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
          &lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"btn btn-primary"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Back Home&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;/section&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/section&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/main&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And here's what the auth page structure looks like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;main&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"auth-page"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;section&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"auth-page-text"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;h1&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"auth-text-heading"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Welcome Back&lt;span class="nt"&gt;&amp;lt;/h1&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;p&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"auth-text-para"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Log in to your LovedIn account&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/section&amp;gt;&lt;/span&gt;

  &lt;span class="nt"&gt;&amp;lt;form&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"auth-form"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;fieldset&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"auth-field"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;legend&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"auth-form-heading"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Login Details&lt;span class="nt"&gt;&amp;lt;/legend&amp;gt;&lt;/span&gt;

      &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"form-group"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;label&lt;/span&gt; &lt;span class="na"&gt;for=&lt;/span&gt;&lt;span class="s"&gt;"email"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Email:&lt;span class="nt"&gt;&amp;lt;/label&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"email"&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"email"&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"email"&lt;/span&gt; &lt;span class="na"&gt;required&lt;/span&gt; &lt;span class="na"&gt;placeholder=&lt;/span&gt;&lt;span class="s"&gt;"you@example.com"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;

      &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"form-group"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;label&lt;/span&gt; &lt;span class="na"&gt;for=&lt;/span&gt;&lt;span class="s"&gt;"password"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Password:&lt;span class="nt"&gt;&amp;lt;/label&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"password"&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"password"&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"password"&lt;/span&gt; &lt;span class="na"&gt;required&lt;/span&gt; &lt;span class="na"&gt;placeholder=&lt;/span&gt;&lt;span class="s"&gt;"Enter your password"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;

      &lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"submit"&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"submit-btn"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Login&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/fieldset&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/form&amp;gt;&lt;/span&gt;

  &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"auth-footer"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;p&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"auth-footer-text"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Don't have an account? &lt;span class="nt"&gt;&amp;lt;a&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"signup.html"&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"redirect-link"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Sign up&lt;span class="nt"&gt;&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/main&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I added Open Graph meta tags so when someone shares this on Twitter or Facebook, it shows a nice preview with the right image and description. Meta tags matter for shareability, and proposals are definitely going to be shared.&lt;/p&gt;

&lt;p&gt;The alt text on the GIFs is descriptive, not just "gif". That's for accessibility and for anyone who can't load the images for whatever reason.&lt;/p&gt;

&lt;h2&gt;
  
  
  SEO Optimization
&lt;/h2&gt;

&lt;p&gt;Each page has a unique, descriptive title tag. The proposal page's title is "LovedIn - Your Proposal". That tells search engines exactly what this page is about. The meta description explains the page in 160 characters, which is what shows up in search results.&lt;/p&gt;

&lt;p&gt;Open Graph tags are crucial for this project because proposals are shareable moments. When someone posts the proposal link on Facebook or Twitter, the preview shows the right image, title, and description. That's Open Graph doing its job. Without it, you'd just see a generic URL.&lt;/p&gt;

&lt;p&gt;The heading hierarchy matters too. I didn't just throw h1, h2, h3 at things randomly. There's one h1 per page, which tells search engines what the main topic is. The h2 is for secondary content. This structure helps Google understand the page better.&lt;/p&gt;

&lt;p&gt;The alt text on images does double duty. It helps people using screen readers understand what the images are, and it also helps search engines understand the images. Good alt text is descriptive and relevant. "Celebration GIF" is better than "image123". "Animated baby raising their arms and cheering excitedly to celebrate the positive response" is even better because it describes exactly what's happening.&lt;/p&gt;

&lt;p&gt;Here's what the meta tags and Open Graph setup looks like in the HTML head:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;head&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;charset=&lt;/span&gt;&lt;span class="s"&gt;"UTF-8"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"viewport"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"width=device-width, initial-scale=1.0"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;

  &lt;span class="nt"&gt;&amp;lt;title&amp;gt;&lt;/span&gt;LovedIn - Your Proposal&lt;span class="nt"&gt;&amp;lt;/title&amp;gt;&lt;/span&gt;

  &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"description"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"A personalized proposal experience created with LovedIn."&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;

  &lt;span class="c"&gt;&amp;lt;!-- Open Graph Tags for Social Sharing --&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;property=&lt;/span&gt;&lt;span class="s"&gt;"og:type"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"website"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;property=&lt;/span&gt;&lt;span class="s"&gt;"og:title"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"LovedIn - Your Proposal"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;property=&lt;/span&gt;&lt;span class="s"&gt;"og:description"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"A personalized proposal experience created with LovedIn."&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;property=&lt;/span&gt;&lt;span class="s"&gt;"og:image"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"https://lovedin.vercel.app/assets/images/meta-proposal.png"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;property=&lt;/span&gt;&lt;span class="s"&gt;"og:url"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"https://lovedin.vercel.app/proposal.html"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;

  &lt;span class="c"&gt;&amp;lt;!-- Twitter Card Tags for Twitter Sharing --&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"twitter:card"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"summary_large_image"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"twitter:title"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"LovedIn - Your Proposal"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"twitter:description"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"A personalized proposal experience created with LovedIn."&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"twitter:image"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"https://lovedin.vercel.app/assets/images/meta-proposal.png"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;

  &lt;span class="c"&gt;&amp;lt;!-- Additional SEO --&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"theme-color"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"#ED4779"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;link&lt;/span&gt; &lt;span class="na"&gt;rel=&lt;/span&gt;&lt;span class="s"&gt;"icon"&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"assets/images/favicon.ico"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/head&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here's what each tag does:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Basic Meta Tags:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;&amp;lt;title&amp;gt;&lt;/code&gt; - Shows up in browser tab and search results. Keep it under 60 characters&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;&amp;lt;meta name="description"&amp;gt;&lt;/code&gt; - Shows under the title in search results. Around 160 characters&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;&amp;lt;meta name="viewport"&amp;gt;&lt;/code&gt; - Makes the site responsive on mobile devices&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Open Graph Tags (for Facebook, LinkedIn, etc.):&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;og:title&lt;/code&gt; - The title shown when someone shares the link&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;og:description&lt;/code&gt; - The description shown when someone shares the link&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;og:image&lt;/code&gt; - The image shown when someone shares the link (this is crucial for proposals because the preview is visual)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;og:url&lt;/code&gt; - The URL of the page&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;og:type&lt;/code&gt; - What type of content this is (website, article, etc.)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Twitter Card Tags (specifically for Twitter/X):&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;twitter:card&lt;/code&gt; - Type of card. "summary_large_image" shows a big preview with image&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;twitter:title&lt;/code&gt; - Title for Twitter&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;twitter:description&lt;/code&gt; - Description for Twitter&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;twitter:image&lt;/code&gt; - Image for Twitter&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The overall structure and content on the page tell a story that search engines can understand. When someone searches for "personalized proposal experience" or "romantic proposal idea", we want these pages to show up. The semantic HTML and clear content structure makes that possible.&lt;/p&gt;

&lt;p&gt;When someone shares the proposal link on Facebook, they see the Scarlet Blush color, the proposal image, and a clear description. That's Open Graph working. It makes sharing the proposal feel special, not like a generic link.&lt;/p&gt;

&lt;p&gt;The overall structure and content on the page tell a story that search engines can understand. When someone searches for "personalized proposal experience" or "romantic proposal idea", we want these pages to show up. The semantic HTML and clear content structure makes that possible.&lt;/p&gt;

&lt;h2&gt;
  
  
  The CSS Architecture
&lt;/h2&gt;

&lt;p&gt;My partner built a comprehensive design system in base.css that defines everything we need: colors, spacing, typography scales, border radius values, shadows, and transition durations. Everything is a variable. I had to learn to use that system properly and extend it where the proposal and auth pages needed something different.&lt;/p&gt;

&lt;p&gt;Here's why this matters. When I was styling the proposal page or the auth pages, I didn't write pixel values or hex codes. I wrote var(--spacing-lg) or var(--color-primary). This sounds like extra work, but it's actually the opposite. It's faster because you're following an established pattern. And if we need to change something across the entire site, we change it once.&lt;/p&gt;

&lt;p&gt;Here's what the design system looks like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nd"&gt;:root&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c"&gt;/* Colors */&lt;/span&gt;
  &lt;span class="py"&gt;--color-primary&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;#e22b3b&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;        &lt;span class="c"&gt;/* Scarlet Blush */&lt;/span&gt;
  &lt;span class="py"&gt;--color-primary-bg&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;#f0d1d7&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;     &lt;span class="c"&gt;/* Pink Carnation */&lt;/span&gt;
  &lt;span class="py"&gt;--color-secondary&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;#ed4779&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;      &lt;span class="c"&gt;/* Wild Strawberry */&lt;/span&gt;
  &lt;span class="py"&gt;--color-secondary-bg&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;#fff6f8&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="py"&gt;--color-accent&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;#fa88bb&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;         &lt;span class="c"&gt;/* Petal Frost */&lt;/span&gt;
  &lt;span class="py"&gt;--color-support&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;#d86a77&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;        &lt;span class="c"&gt;/* Blush Rose */&lt;/span&gt;

  &lt;span class="c"&gt;/* Typography */&lt;/span&gt;
  &lt;span class="py"&gt;--font-display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;"Playfair Display"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;serif&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="py"&gt;--font-body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;"Inter"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;sans-serif&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="py"&gt;--heading-h2&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;2.25rem&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="py"&gt;--heading-h3&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1.875rem&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="c"&gt;/* Spacing */&lt;/span&gt;
  &lt;span class="py"&gt;--spacing-lg&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1.5rem&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="py"&gt;--spacing-md&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1rem&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="py"&gt;--spacing-sm&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0.5rem&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="c"&gt;/* Shapes */&lt;/span&gt;
  &lt;span class="py"&gt;--radius-lg&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;12px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="py"&gt;--radius-2xl&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;20px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="c"&gt;/* Shadows */&lt;/span&gt;
  &lt;span class="py"&gt;--shadow-xl&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="m"&gt;20px&lt;/span&gt; &lt;span class="m"&gt;25px&lt;/span&gt; &lt;span class="m"&gt;-5px&lt;/span&gt; &lt;span class="n"&gt;rgba&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0.1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="c"&gt;/* Transitions */&lt;/span&gt;
  &lt;span class="py"&gt;--transition-base&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;250ms&lt;/span&gt; &lt;span class="n"&gt;ease-in-out&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For the proposal page, the buttons are arranged with flexbox, which is the right choice for this layout. I set display to flex, gap handles the spacing between buttons, justify-content centers them horizontally, and flex-wrap makes sure they stack on smaller screens. This is responsive by default without needing a ton of media queries.&lt;/p&gt;

&lt;p&gt;Here's the button styling for the proposal page:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nc"&gt;.proposal-buttons&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;flex&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="py"&gt;gap&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;var&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;--spacing-lg&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nl"&gt;justify-content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;center&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;flex-wrap&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;wrap&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;margin-top&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;var&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;--spacing-2xl&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nc"&gt;.proposal-buttons__yes&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;background&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;linear-gradient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="m"&gt;135deg&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;var&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;--color-primary&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="n"&gt;var&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;--color-secondary&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nl"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;var&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;--color-white&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nl"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;var&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;--spacing-md&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;var&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;--spacing-2xl&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nl"&gt;border&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;none&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;border-radius&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;var&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;--radius-md&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nl"&gt;font-weight&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;var&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;--font-weight-bold&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nl"&gt;cursor&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;pointer&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;transition&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;var&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;--transition-base&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nl"&gt;box-shadow&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="m"&gt;4px&lt;/span&gt; &lt;span class="m"&gt;12px&lt;/span&gt; &lt;span class="n"&gt;rgba&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;226&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;43&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;59&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0.15&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nc"&gt;.proposal-buttons__no&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;background&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;rgba&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;226&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;43&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;59&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0.08&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nl"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;var&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;--color-primary&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nl"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;var&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;--spacing-md&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;var&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;--spacing-2xl&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nl"&gt;border&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;var&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;--border-width-medium&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nb"&gt;solid&lt;/span&gt; &lt;span class="n"&gt;var&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;--color-primary&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nl"&gt;border-radius&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;var&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;--radius-md&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nl"&gt;cursor&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;pointer&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For the auth pages, the form styling had to feel welcoming while still being functional. Here's the form structure:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nc"&gt;.auth-form&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;background&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;var&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;--color-white&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nl"&gt;border-radius&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;var&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;--radius-lg&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nl"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;var&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;--spacing-4xl&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;var&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;--spacing-2xl&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nl"&gt;max-width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;400px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;100%&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;box-shadow&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;var&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;--shadow-lg&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nl"&gt;border&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;var&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;--border-width-thin&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nb"&gt;solid&lt;/span&gt; &lt;span class="n"&gt;var&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;--color-primary-bg&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nc"&gt;.auth-field&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;border&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;none&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;margin&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;flex&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;flex-direction&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;column&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="py"&gt;gap&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;var&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;--spacing-lg&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nc"&gt;.form-group&lt;/span&gt; &lt;span class="nt"&gt;input&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;var&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;--spacing-md&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;var&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;--spacing-md&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nl"&gt;border&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;var&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;--border-width-medium&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nb"&gt;solid&lt;/span&gt; &lt;span class="n"&gt;var&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;--color-primary-bg&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nl"&gt;border-radius&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;var&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;--radius-md&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nl"&gt;font-family&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;var&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;--font-body&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nl"&gt;font-size&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;var&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;--font-size-sm&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nl"&gt;transition&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;var&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;--transition-base&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nl"&gt;background-color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;var&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;--color-white&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nl"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;var&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;--color-gray-900&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nc"&gt;.form-group&lt;/span&gt; &lt;span class="nt"&gt;input&lt;/span&gt;&lt;span class="nd"&gt;:focus&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;outline&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;none&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;border-color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;var&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;--color-primary&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nl"&gt;box-shadow&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="m"&gt;3px&lt;/span&gt; &lt;span class="n"&gt;rgba&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;226&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;43&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;59&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0.1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I used BEM naming for all the CSS classes. Block, Element, Modifier. This means class names tell you exactly what they're for. .proposal-container is the block. .proposal-container__title is an element inside it. It's clear, it's scalable, and it prevents naming conflicts.&lt;/p&gt;

&lt;p&gt;Here's an example of BEM structure in the proposal container:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nc"&gt;.proposal-container&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;background&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;var&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;--color-white&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nl"&gt;border-radius&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;var&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;--radius-2xl&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nl"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;var&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;--spacing-4xl&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;var&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;--spacing-2xl&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nl"&gt;max-width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;600px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;100%&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;box-shadow&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;var&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;--shadow-xl&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nl"&gt;text-align&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;center&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;position&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;relative&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nc"&gt;.proposal-container__title&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;font-family&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;var&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;--font-display&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nl"&gt;font-size&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;var&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;--heading-h2&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nl"&gt;font-weight&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;var&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;--font-weight-extrabold&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nl"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;var&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;--color-gray-900&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nl"&gt;margin-bottom&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;var&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;--spacing-sm&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nc"&gt;.proposal-container__text&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;font-size&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;var&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;--font-size-md&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nl"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;var&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;--color-gray-500&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nl"&gt;margin-bottom&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;var&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;--spacing-lg&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nl"&gt;font-weight&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;var&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;--font-weight-medium&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I didn't use element selectors like "h1" or "button" for styling. Everything is class-based. This sounds strict, but it's actually really good practice because it decouples your CSS from your HTML. If the HTML structure changes, your CSS doesn't break. And when you're working on a team, this prevents one person's styling decisions from affecting another person's work.&lt;/p&gt;

&lt;h2&gt;
  
  
  The DRY Principle and Button Styles
&lt;/h2&gt;

&lt;p&gt;At first, I had button styles in auth.css. Then I had them again in proposal.css. That's duplication, and it's a problem. If we need to update how buttons look, we'd have to change multiple files. That's asking for bugs.&lt;/p&gt;

&lt;p&gt;So I centralized all button styles in base.css. Now auth pages use them, proposal pages use them, and any other page that comes along uses them. One source of truth. When we update buttons, it happens everywhere automatically.&lt;/p&gt;

&lt;p&gt;This is called the DRY principle: Don't Repeat Yourself. It's one of those fundamentals that sounds obvious until you see how much time it saves you in the long run.&lt;/p&gt;

&lt;h2&gt;
  
  
  Responsive Design
&lt;/h2&gt;

&lt;p&gt;The proposal page, the login page, and the signup page all need to work on phones, tablets, and desktops. The way I handled this was with media queries that adjust sizes and spacing for smaller screens.&lt;/p&gt;

&lt;p&gt;On mobile, the container gets less padding so it fits better. The headings get smaller. Everything is appropriately sized for the device. All of this happens at a breakpoint around 640 pixels wide for the auth pages and 768 pixels for the proposal page, which is where most tablets switch to portrait orientation.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Was Actually Hard
&lt;/h2&gt;

&lt;p&gt;The biggest challenge wasn't the code. It was maintaining consistency while working with someone else on the same project. My partner was building out base.css, the homepage, and stories page while I was working on the proposal page and auth pages. We both needed to use the same button styles, the same colors, the same spacing scale.&lt;/p&gt;

&lt;p&gt;At the beginning, I was using element selectors like "h1" or direct targeting. That works fine until your partner structures their HTML differently, and then suddenly the styling breaks or looks inconsistent. Or you both style buttons and they look slightly different because you made slightly different choices.&lt;/p&gt;

&lt;p&gt;The Git workflow was challenging too. I had to learn how to create proper feature branches, write good commit messages, and handle merge conflicts when they happened. &lt;/p&gt;

&lt;p&gt;Learning to use Git branches properly was key. We established a pattern where each feature got its own branch. I'd create a branch like "feature/proposal-page-styling", do my work, commit with clear messages like "refactor(css): Remove button styling duplication", push that branch, and then create a pull request for my partner to review. Only after they approved would it get merged to the main branch.&lt;/p&gt;

&lt;p&gt;This workflow felt like extra steps at first, but it actually saved us from so many problems. And having code review from my partner meant I caught issues I might have missed.&lt;/p&gt;

&lt;p&gt;Another challenge was getting the responsive design right. The proposal page and auth pages need to look good on phones, tablets, and desktops. Getting padding, font sizes, and button spacing to scale properly across all those sizes took careful testing and tweaking. Mobile design is harder than it looks.&lt;/p&gt;

&lt;p&gt;The solution was establishing a clear system and sticking to it. We documented how classes should be named. We centralized shared styles in base.css. We used variables for everything. Did this take time upfront? Yeah. Was it worth it? Absolutely. Because after that, we could work independently without worrying about breaking each other's work.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I'd Do Differently in Version 2.0
&lt;/h2&gt;

&lt;p&gt;First, I'd add animations to the page transitions. Right now the states are designed to swap with classes, but in version 2 I'd add CSS animations so they fade or slide in smoothly when the state changes.&lt;/p&gt;

&lt;p&gt;Second, I'd improve the back button styling. Currently it's functional, but I'd make it more integrated into the overall design. Maybe animate it on hover or give it more visual feedback.&lt;/p&gt;

&lt;p&gt;Third, more focus on micro-interactions. Things like button hover effects, focus states for keyboard navigation, and smooth transitions everywhere. These small details make a huge difference in how polished something feels.&lt;/p&gt;

&lt;p&gt;Fourth, I'd optimize the layout further for tablets. Right now I have desktop and mobile, but tablets are their own thing. Spending more time on that middle breakpoint would help.&lt;/p&gt;

&lt;p&gt;Fifth, I'd add more sophisticated typography handling. Maybe different heading sizes for different sections, better line heights, better letter spacing. Typography is understated but incredibly important.&lt;/p&gt;

&lt;p&gt;Sixth, I'd consider adding CSS custom properties for even more granular control over things like opacity, blur effects, and other visual effects that might make the page feel more alive.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I Learned
&lt;/h2&gt;

&lt;p&gt;Building this taught me that design systems aren't just about making things look consistent. They're about enabling teams to work together without friction. When everyone follows the same patterns and uses the same variables, the code becomes easier to understand and easier to maintain. My partner laid that foundation with base.css, and I learned to trust it and build on top of it.&lt;/p&gt;

&lt;p&gt;I also learned that constraints are actually helpful. When my partner constantly reinforced that "no element selectors, everything has to be a class", that forced me to think more carefully about naming and structure. &lt;/p&gt;

&lt;p&gt;I learned that CSS can do way more than people think. You don't need JavaScript for a lot of things. Flexbox, media queries, CSS variables, hover states, they're all super powerful. Learning to work within CSS constraints made me a better developer.&lt;/p&gt;

&lt;p&gt;Finally, I learned that responsive design is an art. Getting something to look good on a 5-inch phone and a 27-inch monitor takes real thought. It's not just about making things smaller or bigger. It's about understanding how people interact with different screen sizes and designing for that.&lt;/p&gt;

&lt;p&gt;I also learned something about working with another person on code. It requires vulnerability. You have to be willing to have your code reviewed, to hear that something doesn't work, to try a different approach. It requires patience. Sometimes the person working on the foundations (like base.css) is the unsung hero because their work enables everything else. And it requires trust. Trust that your partner is doing their part, trust that their approach is intentional, trust that they care about the outcome as much as you do.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Live Experience
&lt;/h2&gt;

&lt;p&gt;You can check out the proposal page here: &lt;a href="https://lovedin.vercel.app/" rel="noopener noreferrer"&gt;https://lovedin.vercel.app/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The code is all on GitHub: &lt;a href="https://github.com/Yourgotopyromaniac/lovedin" rel="noopener noreferrer"&gt;https://github.com/Yourgotopyromaniac/lovedin&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The design system documentation that guided all of this: &lt;a href="https://tidy-nape-704.notion.site/LovedIn-Design-Documentation-2fcff83f0c4c80cea70bfefc37e883e0" rel="noopener noreferrer"&gt;https://tidy-nape-704.notion.site/LovedIn-Design-Documentation-2fcff83f0c4c80cea70bfefc37e883e0&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The broader case study for the whole project: &lt;a href="https://docs.google.com/document/d/1BwLFD08gpjclHfZflFJPF8wNfVAWR2nbD_FLrHhudEE/edit" rel="noopener noreferrer"&gt;https://docs.google.com/document/d/1BwLFD08gpjclHfZflFJPF8wNfVAWR2nbD_FLrHhudEE/edit&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Acknowledgment
&lt;/h2&gt;

&lt;p&gt;This happened because of collaboration. My partner Awoyemi Abiola did the heavy lifting on this project. They built the base.css design system that everything else is built on top of, styled the index.html landing page, and created the stories.html page and its styling. Without that foundation, my work on the proposal page and the auth pages would have been way harder.&lt;/p&gt;

&lt;p&gt;We had to sync up, make decisions together, and trust each other's work. That's how you build something actually good. When I was building the proposal page and auth pages, I could rely on the design system Awoyemi created. When they were styling the homepage, they could count on the system being consistent.&lt;/p&gt;

&lt;p&gt;Check out Awoyemi's GitHub: &lt;a href="https://github.com/Yourgotopyromaniac" rel="noopener noreferrer"&gt;https://github.com/Yourgotopyromaniac&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And their version of this case study:&lt;/p&gt;




</description>
    </item>
  </channel>
</rss>
