Polish an AI Website Into a Client Product
Transform a raw AI-generated site into a professional, deployed web product.
Introduction
30 Second Summary
AI tools can generate a website in seconds, but the output always looks generic. Clients don't pay for "good enough." They pay for polish.
In this project, you will take a raw AI-generated coffee shop website and transform it into a professional client deliverable. You'll fix typography, spacing, interactions, and mobile responsiveness, then deploy the finished site live on Vercel with a shareable URL.
What You'll Build
A complete multi-section business website polished to professional standards using targeted CSS edits, deployed live on the internet.
By the end of this project, you'll have:
- A polished coffee shop website with a hero section, menu grid, about section, and contact form.
- Professional typography, spacing, hover interactions, and mobile responsiveness that separates paid work from free AI output.
- A live deployed site on Vercel with a shareable URL you can send to anyone.
- Secret Mission: Add smooth scroll navigation and animated section reveals that make the site feel premium.
Are there any prerequisites?
None. This project includes full setup instructions for every tool you'll need, including Cursor (your code editor), Node.js, and the Vercel CLI.
Create the Raw AI-Generated Site
Your tools are installed and your project folder is ready. Now it's time to build the actual website you'll be polishing throughout this project.
In this step, you'll create a coffee shop website that deliberately mimics what AI tools like Lovable or v0 typically generate. The result will look functional but unpolished. That "before" state is the starting point for every improvement you'll make in later steps.
In this step, get ready to:
- Create the HTML structure for the coffee shop site.
- Add basic CSS styling that simulates AI output.
- Preview the "before" state in your browser.
Create the HTML file
Every website starts with an index.html file. This is the file your browser reads first when opening a site. You'll paste in a multi-section coffee shop page that represents typical AI-generated output.
- In Cursor's Explorer sidebar on the left, hover over the COFFEE-SHOP-SITE heading.
- Click the new file icon (the page icon with a + symbol) that appears when you hover.
- Type index.html and press Enter.
- The file opens in the editor. Paste the following code into it:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Brew & Co. | Specialty Coffee</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<!-- Hero section: the big banner visitors see first -->
<section class="hero" id="hero">
<div class="hero-content">
<h1>Brew & Co.</h1>
<p class="hero-tagline">Specialty coffee, crafted with care since 2018.</p>
<a href="#menu" class="btn">View Our Menu</a>
</div>
</section>
<!-- Menu section: displays the drink options -->
<section class="menu" id="menu">
<h2>Our Menu</h2>
<div class="menu-grid">
<div class="menu-card">
<h3>Espresso</h3>
<p>Rich, bold, and perfectly pulled. Our house blend is roasted locally every week.</p>
<span class="price">$4.50</span>
</div>
<div class="menu-card">
<h3>Oat Latte</h3>
<p>Silky oat milk paired with a double shot. Creamy without the dairy.</p>
<span class="price">$6.00</span>
</div>
<div class="menu-card">
<h3>Cold Brew</h3>
<p>Steeped for 18 hours. Smooth, low-acid, and served over ice.</p>
<span class="price">$5.50</span>
</div>
<div class="menu-card">
<h3>Matcha Latte</h3>
<p>Ceremonial-grade matcha whisked with your choice of milk.</p>
<span class="price">$6.50</span>
</div>
<div class="menu-card">
<h3>Drip Coffee</h3>
<p>Simple, fresh, and brewed every 30 minutes. Always hot.</p>
<span class="price">$3.50</span>
</div>
<div class="menu-card">
<h3>Chai Latte</h3>
<p>House-made chai with cinnamon, cardamom, and ginger. Spiced perfectly.</p>
<span class="price">$5.50</span>
</div>
</div>
</section>
<!-- About section: the shop's story -->
<section class="about" id="about">
<h2>Our Story</h2>
<div class="about-content">
<p>Brew & Co. started as a small cart at the local farmers market. Today, we serve hundreds of cups daily from our cozy storefront on Elm Street. We believe great coffee starts with great relationships: with our farmers, our roasters, and our community.</p>
<p>Every bean is ethically sourced and roasted within 50 miles of our shop. We're not just making coffee. We're building a neighborhood.</p>
</div>
</section>
<!-- Contact section: address, hours, and a message form -->
<section class="contact" id="contact">
<h2>Visit Us</h2>
<div class="contact-content">
<div class="contact-info">
<p><strong>Address</strong><br>142 Elm Street, Portland, OR 97201</p>
<p><strong>Hours</strong><br>Mon-Fri: 7am - 5pm<br>Sat-Sun: 8am - 4pm</p>
<p><strong>Phone</strong><br>(503) 555-0142</p>
</div>
<form class="contact-form">
<input type="text" placeholder="Your Name" required>
<input type="email" placeholder="Your Email" required>
<textarea placeholder="Your Message" rows="4" required></textarea>
<button type="submit" class="btn">Send Message</button>
</form>
</div>
</section>
<footer>
<p>© 2025 Brew & Co. All rights reserved.</p>
</footer>
</body>
</html>
What does this code do?
This HTML creates a four-section coffee shop website:
- Hero: a full-width banner with the shop name, tagline, and a button.
- Menu: six drink cards, each with a name, description, and price.
- About: the shop's backstory in two paragraphs.
- Contact: address info alongside a simple message form.
Each section has an id attribute (like id="menu") so links can jump straight to that section. The <link rel="stylesheet" href="style.css"> in the <head> connects this page to the stylesheet you'll create next.
- Save the file by pressing Cmd+S (macOS) or Ctrl+S (Windows).
Don't see index.html in the sidebar?
- Make sure you typed the filename as index.html (not Index.html or index.html.txt).
- If the Explorer sidebar isn't visible, press Cmd+Shift+E (macOS) or Ctrl+Shift+E (Windows) to open it.
- help me create a new file in Cursor
Create the stylesheet
The stylesheet controls how your HTML looks in the browser. This basic version uses Arial, flat colors, and minimal spacing. It's intentionally generic to simulate typical AI output.
- In the Explorer sidebar, click the new file icon again.
- Type style.css and press Enter.
- Paste the following code into the new file:
/* Basic generic styles simulating raw AI output */
body {
font-family: Arial, sans-serif;
margin: 0;
padding: 0;
color: #333;
}
h1, h2, h3 {
font-weight: bold;
}
.hero {
background: #333;
color: white;
padding: 40px 20px;
text-align: center;
}
.btn {
display: inline-block;
padding: 10px 20px;
background: #c9a96e;
color: #000;
text-decoration: none;
border-radius: 4px;
border: none;
cursor: pointer;
}
.menu, .about, .contact {
padding: 40px 20px;
}
.menu-grid {
display: flex;
flex-wrap: wrap;
gap: 16px;
}
.menu-card {
background: #fff;
border: 1px solid #ccc;
padding: 16px;
flex: 1 1 200px;
}
.price {
font-weight: bold;
}
.contact-content {
display: flex;
gap: 20px;
}
.contact-form {
display: flex;
flex-direction: column;
gap: 8px;
}
.contact-form input,
.contact-form textarea {
padding: 8px;
border: 1px solid #ccc;
border-radius: 4px;
}
footer {
text-align: center;
padding: 20px;
background: #333;
color: #fff;
}
What does this stylesheet do?
This CSS gives the page a bare-minimum look. It uses the system font Arial, sets a flat dark background on the hero, and arranges the menu cards with basic flexbox.
Notice what's missing: no font pairing, no type scale, no hover effects, no transitions, cramped padding, and no responsive breakpoints for mobile. Those are exactly the things you'll add in the next steps.
- Save style.css by pressing Cmd+S (macOS) or Ctrl+S (Windows).
File not saving?
- Check for a white dot on the file tab in Cursor. A dot means unsaved changes.
- Make sure you're clicking inside the editor area (not the sidebar) before pressing the save shortcut.
- help me save a file in Cursor
✔️ Awesome, I've got everything!
Great. Make sure both files are saved. You should see index.html and style.css listed side by side in the Explorer sidebar.
ⓧ I'd like to double check the full code
Here's the full index.html:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Brew & Co. | Specialty Coffee</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<section class="hero" id="hero">
<div class="hero-content">
<h1>Brew & Co.</h1>
<p class="hero-tagline">Specialty coffee, crafted with care since 2018.</p>
<a href="#menu" class="btn">View Our Menu</a>
</div>
</section>
<section class="menu" id="menu">
<h2>Our Menu</h2>
<div class="menu-grid">
<div class="menu-card">
<h3>Espresso</h3>
<p>Rich, bold, and perfectly pulled. Our house blend is roasted locally every week.</p>
<span class="price">$4.50</span>
</div>
<div class="menu-card">
<h3>Oat Latte</h3>
<p>Silky oat milk paired with a double shot. Creamy without the dairy.</p>
<span class="price">$6.00</span>
</div>
<div class="menu-card">
<h3>Cold Brew</h3>
<p>Steeped for 18 hours. Smooth, low-acid, and served over ice.</p>
<span class="price">$5.50</span>
</div>
<div class="menu-card">
<h3>Matcha Latte</h3>
<p>Ceremonial-grade matcha whisked with your choice of milk.</p>
<span class="price">$6.50</span>
</div>
<div class="menu-card">
<h3>Drip Coffee</h3>
<p>Simple, fresh, and brewed every 30 minutes. Always hot.</p>
<span class="price">$3.50</span>
</div>
<div class="menu-card">
<h3>Chai Latte</h3>
<p>House-made chai with cinnamon, cardamom, and ginger. Spiced perfectly.</p>
<span class="price">$5.50</span>
</div>
</div>
</section>
<section class="about" id="about">
<h2>Our Story</h2>
<div class="about-content">
<p>Brew & Co. started as a small cart at the local farmers market. Today, we serve hundreds of cups daily from our cozy storefront on Elm Street. We believe great coffee starts with great relationships: with our farmers, our roasters, and our community.</p>
<p>Every bean is ethically sourced and roasted within 50 miles of our shop. We're not just making coffee. We're building a neighborhood.</p>
</div>
</section>
<section class="contact" id="contact">
<h2>Visit Us</h2>
<div class="contact-content">
<div class="contact-info">
<p><strong>Address</strong><br>142 Elm Street, Portland, OR 97201</p>
<p><strong>Hours</strong><br>Mon-Fri: 7am - 5pm<br>Sat-Sun: 8am - 4pm</p>
<p><strong>Phone</strong><br>(503) 555-0142</p>
</div>
<form class="contact-form">
<input type="text" placeholder="Your Name" required>
<input type="email" placeholder="Your Email" required>
<textarea placeholder="Your Message" rows="4" required></textarea>
<button type="submit" class="btn">Send Message</button>
</form>
</div>
</section>
<footer>
<p>© 2025 Brew & Co. All rights reserved.</p>
</footer>
</body>
</html>
And here's the full style.css:
/* Basic generic styles simulating raw AI output */
body {
font-family: Arial, sans-serif;
margin: 0;
padding: 0;
color: #333;
}
h1, h2, h3 {
font-weight: bold;
}
.hero {
background: #333;
color: white;
padding: 40px 20px;
text-align: center;
}
.btn {
display: inline-block;
padding: 10px 20px;
background: #c9a96e;
color: #000;
text-decoration: none;
border-radius: 4px;
border: none;
cursor: pointer;
}
.menu, .about, .contact {
padding: 40px 20px;
}
.menu-grid {
display: flex;
flex-wrap: wrap;
gap: 16px;
}
.menu-card {
background: #fff;
border: 1px solid #ccc;
padding: 16px;
flex: 1 1 200px;
}
.price {
font-weight: bold;
}
.contact-content {
display: flex;
gap: 20px;
}
.contact-form {
display: flex;
flex-direction: column;
gap: 8px;
}
.contact-form input,
.contact-form textarea {
padding: 8px;
border: 1px solid #ccc;
border-radius: 4px;
}
footer {
text-align: center;
padding: 20px;
background: #333;
color: #fff;
}
Preview the site in your browser
Time to see what a raw AI-generated site looks like. You'll open the HTML file directly in your browser to get a clear picture of the "before" state.
- In Cursor's Explorer sidebar, right-click on index.html.
- Select Reveal in Finder (macOS) or Reveal in File Explorer (Windows).
- Double-click index.html in the file manager window that opens. It opens in your default browser.
You should see a basic coffee shop page with a dark hero banner at the top, menu cards below it, an about section, and a contact form at the bottom.
What should I notice?
Look at the page with a critical eye. This is what clients see when they get raw AI output:
- The font is Arial. Functional, but generic.
- Spacing feels cramped and inconsistent between sections.
- Buttons do nothing on hover. No visual feedback.
- On a narrow screen, the menu cards stack awkwardly.
Each of these problems is something you'll fix in the upcoming steps. By the end, the same page will look like a $1,500 deliverable.
See unstyled text with no colors?
- Make sure style.css is in the same folder as index.html. Both files should appear side by side in the Explorer sidebar.
- Check that the filename is exactly style.css (not styles.css or style.CSS). The <link> tag in the HTML looks for style.css exactly.
- help me fix my stylesheet not loading
You've now got the raw starting material. Next up, you'll transform this generic page into something professional by fixing the typography and visual hierarchy.
Fix Typography and Visual Hierarchy
The biggest giveaway of an AI-generated site is generic typography. Default system fonts, uniform heading sizes, and cramped line-height all scream "template."
Professional designers choose font pairings with intention: one font for personality (headings), another for readability (body text). In this step, you'll swap the generic Arial for a curated Google Fonts pairing and establish a deliberate size hierarchy.
In this step, get ready to:
- Load a professional font pairing from Google Fonts.
- Establish a consistent type scale for all headings.
- Tune paragraph readability with proper sizing and line length.
Swap to a professional font pairing
Google Fonts lets you load high-quality typefaces for free. You'll use Playfair Display (a serif with personality) for headings and Inter (a clean sans-serif) for body text.
- In Cursor, open index.html from the Explorer sidebar on the left.
- Find the <link rel="stylesheet" href="style.css"> line in the <head> section.
- Add the following three lines directly above that stylesheet link:
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600&family=Playfair+Display:wght@600;700&display=swap" rel="stylesheet">
What do these lines do?
The two preconnect links tell your browser to start connecting to Google's font servers early, so fonts load faster.
The third link loads the actual font files. It pulls Inter (weights 400, 500, 600) for body text and Playfair Display (weights 600, 700) for headings.
- Save index.html.
Now you need to tell your CSS to actually use these fonts. You'll replace the current generic stylesheet with a proper reset and base configuration.
- Open style.css in Cursor.
- Select all the existing content (Cmd+A on macOS, Ctrl+A on Windows) and delete it.
- Paste the following reset and base styles:
/* === RESET & BASE === */
*, *::before, *::after {
margin: 0;
padding: 0;
box-sizing: border-box;
}
html {
scroll-behavior: smooth;
}
body {
font-family: 'Inter', sans-serif;
font-size: 1.125rem;
line-height: 1.7;
color: #2c2c2c;
background-color: #fdfbf7;
}
What does this code do?
The * reset removes all default browser margins and padding so you have full control over spacing.
The body rule sets Inter as the base font for all text on the page. The warm off-white background (#fdfbf7) replaces the harsh default white, making text easier on the eyes.
- Save style.css and refresh your browser.
- You should see the body text switch from Arial to a cleaner sans-serif font (Inter). The background turns to a warm cream color.
Still seeing Arial?
Make sure the three Google Fonts <link> tags are inside your <head> section and appear before the style.css link.
Check that the font name in your CSS matches exactly: 'Inter' with a capital I and single quotes.
Help me figure out why my Google Fonts aren't loading.
Establish a type scale
A type scale gives your headings a clear visual hierarchy. Each level gets a deliberately chosen size so readers instantly understand which text is most important.
- In style.css, add the following typography rules below the body rule:
/* === TYPOGRAPHY === */
h1, h2, h3 {
font-family: 'Playfair Display', serif;
font-weight: 700;
line-height: 1.2;
color: #1a1a1a;
}
h1 {
font-size: 3.5rem;
letter-spacing: -0.02em;
}
h2 {
font-size: 2.5rem;
letter-spacing: -0.01em;
margin-bottom: 2rem;
text-align: center;
}
h3 {
font-size: 1.5rem;
margin-bottom: 0.5rem;
}
p {
max-width: 65ch;
}
Why these specific sizes?
The ratio between sizes (3.5, 2.5, 1.5 rem) creates a clear visual ladder. Readers can instantly tell a page title from a section heading from a card title without reading a word.
Negative letter-spacing on large headings tightens the letters slightly, which looks natural at big sizes. At small sizes, default spacing is fine.
- Save style.css and refresh your browser.
- Your headings now use the serif font (Playfair Display) and appear in distinctly different sizes. The "Brew & Co." title should look dramatically larger than section headings like "Our Menu."
Headings all look the same size?
Make sure you have both the grouped rule (h1, h2, h3) AND the individual rules (h1 { }, h2 { }, h3 { }). The grouped rule sets the font. The individual rules set the sizes.
Help me debug my CSS type scale not applying correctly.
Tune paragraph readability
Typography is only half the battle. The remaining styles need to support your new font choices. The hero section, buttons, and other elements need updating to match the professional look.
- In style.css, add the following styles below the typography section to complete the stylesheet:
/* === HERO === */
.hero {
min-height: 100vh;
display: flex;
align-items: center;
justify-content: center;
text-align: center;
padding: 2rem;
background: linear-gradient(135deg, #2c1810 0%, #4a2c20 100%);
color: #fdfbf7;
}
.hero h1 {
color: #fdfbf7;
margin-bottom: 1rem;
}
.hero-tagline {
font-size: 1.25rem;
opacity: 0.9;
margin-bottom: 2rem;
}
/* === BUTTONS === */
.btn {
display: inline-block;
padding: 0.875rem 2rem;
background-color: #c9a96e;
color: #1a1a1a;
text-decoration: none;
font-weight: 600;
font-size: 1rem;
border-radius: 4px;
border: none;
cursor: pointer;
}
/* === SECTIONS === */
.menu, .about, .contact {
padding: 40px 20px;
}
/* === MENU === */
.menu-grid {
display: flex;
flex-wrap: wrap;
gap: 16px;
}
.menu-card {
background: #fff;
border: 1px solid #ccc;
padding: 16px;
flex: 1 1 200px;
}
.price {
font-weight: bold;
color: #4a2c20;
}
/* === CONTACT === */
.contact-content {
display: flex;
gap: 20px;
}
.contact-form {
display: flex;
flex-direction: column;
gap: 8px;
}
.contact-form input,
.contact-form textarea {
padding: 8px;
border: 1px solid #ccc;
border-radius: 4px;
font-family: 'Inter', sans-serif;
font-size: 1rem;
}
/* === FOOTER === */
footer {
text-align: center;
padding: 20px;
background-color: #1a1a1a;
color: #999;
font-size: 0.875rem;
}
What's happening here?
The hero now fills the full viewport height (min-height: 100vh) with a rich coffee-toned gradient. This creates a dramatic first impression that draws the eye to your 3.5rem headline.
The form inputs inherit your Inter font so they match the rest of the page. Small details like this prevent the "patchwork" feel of AI-generated sites.
The p { max-width: 65ch } rule from earlier limits paragraph lines to roughly 65 characters. Research shows lines beyond 75 characters become hard to track, so this keeps every paragraph on your site comfortable to read.
- Save style.css and refresh your browser.
- The hero section now fills the entire screen with a dark gradient, and "Brew & Co." appears large and centered. Scroll down to see the section headings in the serif font at different sizes.
Hero section looks broken or cramped?
Make sure the reset at the top of your file includes margin: 0 and padding: 0. Without the reset, browser defaults add space around the body that prevents the hero from stretching edge-to-edge.
Check that .hero has min-height: 100vh (not just height). Using min-height lets the section grow if content needs more space.
Help me fix my hero section layout.
✔️ Awesome, I've got everything!
Great. Double check you've saved both files before moving on.
ⓧ I'd like to double check the full code
Here's what your index.html should look like:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Brew & Co. | Specialty Coffee</title>
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600&family=Playfair+Display:wght@600;700&display=swap" rel="stylesheet">
<link rel="stylesheet" href="style.css">
</head>
<body>
<section class="hero" id="hero">
<div class="hero-content">
<h1>Brew & Co.</h1>
<p class="hero-tagline">Specialty coffee, crafted with care since 2018.</p>
<a href="#menu" class="btn">View Our Menu</a>
</div>
</section>
<section class="menu" id="menu">
<h2>Our Menu</h2>
<div class="menu-grid">
<div class="menu-card">
<h3>Espresso</h3>
<p>Rich, bold, and perfectly pulled. Our house blend is roasted locally every week.</p>
<span class="price">$4.50</span>
</div>
<div class="menu-card">
<h3>Oat Latte</h3>
<p>Silky oat milk paired with a double shot. Creamy without the dairy.</p>
<span class="price">$6.00</span>
</div>
<div class="menu-card">
<h3>Cold Brew</h3>
<p>Steeped for 18 hours. Smooth, low-acid, and served over ice.</p>
<span class="price">$5.50</span>
</div>
<div class="menu-card">
<h3>Matcha Latte</h3>
<p>Ceremonial-grade matcha whisked with your choice of milk.</p>
<span class="price">$6.50</span>
</div>
<div class="menu-card">
<h3>Drip Coffee</h3>
<p>Simple, fresh, and brewed every 30 minutes. Always hot.</p>
<span class="price">$3.50</span>
</div>
<div class="menu-card">
<h3>Chai Latte</h3>
<p>House-made chai with cinnamon, cardamom, and ginger. Spiced perfectly.</p>
<span class="price">$5.50</span>
</div>
</div>
</section>
<section class="about" id="about">
<h2>Our Story</h2>
<div class="about-content">
<p>Brew & Co. started as a small cart at the local farmers market. Today, we serve hundreds of cups daily from our cozy storefront on Elm Street. We believe great coffee starts with great relationships: with our farmers, our roasters, and our community.</p>
<p>Every bean is ethically sourced and roasted within 50 miles of our shop. We're not just making coffee. We're building a neighborhood.</p>
</div>
</section>
<section class="contact" id="contact">
<h2>Visit Us</h2>
<div class="contact-content">
<div class="contact-info">
<p><strong>Address</strong><br>142 Elm Street, Portland, OR 97201</p>
<p><strong>Hours</strong><br>Mon-Fri: 7am - 5pm<br>Sat-Sun: 8am - 4pm</p>
<p><strong>Phone</strong><br>(503) 555-0142</p>
</div>
<form class="contact-form">
<input type="text" placeholder="Your Name" required>
<input type="email" placeholder="Your Email" required>
<textarea placeholder="Your Message" rows="4" required></textarea>
<button type="submit" class="btn">Send Message</button>
</form>
</div>
</section>
<footer>
<p>© 2025 Brew & Co. All rights reserved.</p>
</footer>
</body>
</html>
Here's what your style.css should look like:
/* === RESET & BASE === */
*, *::before, *::after {
margin: 0;
padding: 0;
box-sizing: border-box;
}
html {
scroll-behavior: smooth;
}
body {
font-family: 'Inter', sans-serif;
font-size: 1.125rem;
line-height: 1.7;
color: #2c2c2c;
background-color: #fdfbf7;
}
/* === TYPOGRAPHY === */
h1, h2, h3 {
font-family: 'Playfair Display', serif;
font-weight: 700;
line-height: 1.2;
color: #1a1a1a;
}
h1 {
font-size: 3.5rem;
letter-spacing: -0.02em;
}
h2 {
font-size: 2.5rem;
letter-spacing: -0.01em;
margin-bottom: 2rem;
text-align: center;
}
h3 {
font-size: 1.5rem;
margin-bottom: 0.5rem;
}
p {
max-width: 65ch;
}
/* === HERO === */
.hero {
min-height: 100vh;
display: flex;
align-items: center;
justify-content: center;
text-align: center;
padding: 2rem;
background: linear-gradient(135deg, #2c1810 0%, #4a2c20 100%);
color: #fdfbf7;
}
.hero h1 {
color: #fdfbf7;
margin-bottom: 1rem;
}
.hero-tagline {
font-size: 1.25rem;
opacity: 0.9;
margin-bottom: 2rem;
}
/* === BUTTONS === */
.btn {
display: inline-block;
padding: 0.875rem 2rem;
background-color: #c9a96e;
color: #1a1a1a;
text-decoration: none;
font-weight: 600;
font-size: 1rem;
border-radius: 4px;
border: none;
cursor: pointer;
}
/* === SECTIONS === */
.menu, .about, .contact {
padding: 40px 20px;
}
/* === MENU === */
.menu-grid {
display: flex;
flex-wrap: wrap;
gap: 16px;
}
.menu-card {
background: #fff;
border: 1px solid #ccc;
padding: 16px;
flex: 1 1 200px;
}
.price {
font-weight: bold;
color: #4a2c20;
}
/* === CONTACT === */
.contact-content {
display: flex;
gap: 20px;
}
.contact-form {
display: flex;
flex-direction: column;
gap: 8px;
}
.contact-form input,
.contact-form textarea {
padding: 8px;
border: 1px solid #ccc;
border-radius: 4px;
font-family: 'Inter', sans-serif;
font-size: 1rem;
}
/* === FOOTER === */
footer {
text-align: center;
padding: 20px;
background-color: #1a1a1a;
color: #999;
font-size: 0.875rem;
}
Your site already looks dramatically different. The font pairing and type scale alone lift it from "AI template" to "someone designed this." Next up, you'll fix the spacing and layout to give everything room to breathe.
Fix Spacing and Layout
Your typography looks sharp, but the page still feels like it was slapped together. Sections are crammed against each other, cards sit at awkward widths, and there is no visual breathing room between elements.
Spacing is what separates amateur layouts from professional ones. In this step, you will apply consistent padding to every section, add deliberate whitespace between elements, and replace the AI's basic flexbox with a proper CSS Grid layout.
In this step, get ready to:
- Apply consistent 6rem padding to all content sections.
- Add deliberate whitespace between headings, paragraphs, and cards.
- Replace the flexbox layout with CSS Grid for the menu and contact sections.
Apply consistent section padding
Every content section on the page currently uses tight, pixel-based padding. Professional sites give their sections generous, equal vertical space so content can breathe.
- In style.css, find the /* === SECTIONS === */ comment and the rule below it.
- Replace the entire .menu, .about, .contact rule with this updated version:
/* === SECTIONS === */
.menu, .about, .contact {
padding: 6rem 2rem;
max-width: 1200px;
margin: 0 auto;
}
What does this code do?
- padding: 6rem 2rem gives every section generous vertical breathing room (6rem top and bottom) with comfortable horizontal padding.
- max-width: 1200px prevents content from stretching too wide on large monitors.
- margin: 0 auto centers each section horizontally within the page.
The About section needs a background color that spans the full width of the page. You will add a dedicated section for it that overrides the max-width constraint.
- Below the /* === MENU === */ section (after the .price rule), add this new About section:
/* === ABOUT === */
.about {
background-color: #f5f0e8;
max-width: 100%;
padding: 6rem 2rem;
}
.about-content {
max-width: 800px;
margin: 0 auto;
text-align: center;
}
.about-content p {
margin: 0 auto 1.5rem auto;
}
What does this code do?
- .about sets a warm cream background and overrides max-width to 100% so the color stretches edge to edge.
- .about-content constrains the text inside to 800px and centers it for readability.
- .about-content p adds consistent 1.5rem spacing below each paragraph.
The footer also needs updated padding to match the new system.
- In style.css, scroll down to the /* === FOOTER === */ section.
- Find this line:
padding: 20px;
- Replace 20px with 2rem, so the line now looks like this:
padding: 2rem;
- Save style.css and refresh your browser.
- You should see much more vertical space between sections. The About section now has a warm cream background that spans the full page width.
Sections still look cramped?
- Make sure you replaced the entire .menu, .about, .contact rule (including the old padding: 40px 20px) instead of adding a second copy below it.
- Check that the .about override comes AFTER the shared sections rule. CSS reads top to bottom, so order matters.
- help me figure out why my section padding isn't showing up
Add whitespace between elements
Sections are spaced out, but elements inside them are still jammed together. Consistent margins between cards, paragraphs, and form fields create the visual rhythm of a professional layout.
- In style.css, find the .menu-card rule in the /* === MENU === */ section.
- Directly below .menu-card, add this new rule for paragraph spacing inside cards:
.menu-card p {
color: #555;
margin-bottom: 1rem;
}
What does this code do?
This targets the description paragraph inside each menu card. The margin-bottom: 1rem pushes the price away from the description so they do not collide visually.
- Now scroll down to the /* === CONTACT === */ section and add this rule below .contact-content:
.contact-info p {
margin-bottom: 1.5rem;
}
- Still in the contact section, find the .contact-form rule. Replace it and the .contact-form input, .contact-form textarea rule with these updated versions:
.contact-form {
display: flex;
flex-direction: column;
gap: 1rem;
}
.contact-form input,
.contact-form textarea {
padding: 0.875rem 1rem;
border: 1px solid #ddd;
border-radius: 4px;
font-family: 'Inter', sans-serif;
font-size: 1rem;
}
What changed here?
- The form gap increased from 8px to 1rem so inputs are not packed tightly together.
- Input padding grew from 8px to 0.875rem 1rem, making fields feel more spacious and easier to tap on mobile.
- The border color softened from #ccc to #ddd for a subtler look.
- Save style.css and refresh your browser.
- Check the menu cards. There should be clear space between each description and its price. The contact form fields should look more spacious and evenly distributed.
Contact info items still cramped?
- Make sure you placed the .contact-info p rule inside the /* === CONTACT === */ section, not inside the About section by mistake.
- Confirm you saved the file. Unsaved edits in Cursor show a dot on the file tab.
- help me debug my contact section spacing
Fix the card grid
The menu currently uses basic flexbox, which wraps cards at unpredictable widths. CSS Grid gives you explicit control over how many columns display and how they respond to different screen sizes.
- In the /* === MENU === */ section of style.css, find the .menu-grid, .menu-card, and .price rules.
- Replace all three rules with this updated version:
/* === MENU === */
.menu-grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 2rem;
margin-top: 2rem;
}
.menu-card {
background: #ffffff;
padding: 2rem;
border-radius: 8px;
border: 1px solid #eee;
}
.menu-card p {
color: #555;
margin-bottom: 1rem;
}
.price {
font-weight: 600;
color: #4a2c20;
font-size: 1.25rem;
}
What does this code do?
- display: grid switches from flexbox to CSS Grid, giving you precise column control.
- grid-template-columns: repeat(3, 1fr) creates exactly three equal-width columns.
- The cards get more padding, rounded corners, and a softer border color (#eee instead of #ccc) for a polished look.
- The price gets a larger font size (1.25rem) so it stands out as a key piece of information.
The contact section also uses basic flexbox. You will replace it with a two-column grid that gives the info and form equal space.
- In the /* === CONTACT === */ section, find the .contact-content rule.
- Replace it with this grid-based version:
.contact-content {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 4rem;
margin-top: 2rem;
}
What does this code do?
- grid-template-columns: 1fr 1fr splits the contact area into two equal halves (info on the left, form on the right).
- gap: 4rem adds generous breathing room between the two columns so they do not feel crowded.
- margin-top: 2rem separates the grid from the section heading above it.
- Save style.css and refresh your browser.
- The menu should now display as a clean 3-column grid of equally sized cards. The contact section should show the address info and form side by side with generous space between them.
Cards not lining up in three columns?
- Check that you replaced display: flex with display: grid in .menu-grid. If both are present, the old flex rule may be overriding the grid.
- Make sure you removed the old flex: 1 1 200px line from .menu-card. Leftover flex properties conflict with grid.
- help me fix my CSS Grid layout for the menu cards
✔️ Awesome, I've got everything!
Great. Double check you have saved style.css before moving on.
ⓧ I'd like to double check the full code
Here is the full style.css as it should look at the end of this step:
/* === RESET & BASE === */
*, *::before, *::after {
margin: 0;
padding: 0;
box-sizing: border-box;
}
html {
scroll-behavior: smooth;
}
body {
font-family: 'Inter', sans-serif;
font-size: 1.125rem;
line-height: 1.7;
color: #2c2c2c;
background-color: #fdfbf7;
}
/* === TYPOGRAPHY === */
h1, h2, h3 {
font-family: 'Playfair Display', serif;
font-weight: 700;
line-height: 1.2;
color: #1a1a1a;
}
h1 {
font-size: 3.5rem;
letter-spacing: -0.02em;
}
h2 {
font-size: 2.5rem;
letter-spacing: -0.01em;
margin-bottom: 2rem;
text-align: center;
}
h3 {
font-size: 1.5rem;
margin-bottom: 0.5rem;
}
p {
max-width: 65ch;
}
/* === HERO === */
.hero {
min-height: 100vh;
display: flex;
align-items: center;
justify-content: center;
text-align: center;
padding: 2rem;
background: linear-gradient(135deg, #2c1810 0%, #4a2c20 100%);
color: #fdfbf7;
}
.hero h1 {
color: #fdfbf7;
margin-bottom: 1rem;
}
.hero-tagline {
font-size: 1.25rem;
opacity: 0.9;
margin-bottom: 2rem;
}
/* === BUTTONS === */
.btn {
display: inline-block;
padding: 0.875rem 2rem;
background-color: #c9a96e;
color: #1a1a1a;
text-decoration: none;
font-weight: 600;
font-size: 1rem;
border-radius: 4px;
border: none;
cursor: pointer;
}
/* === SECTIONS === */
.menu, .about, .contact {
padding: 6rem 2rem;
max-width: 1200px;
margin: 0 auto;
}
/* === MENU === */
.menu-grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 2rem;
margin-top: 2rem;
}
.menu-card {
background: #ffffff;
padding: 2rem;
border-radius: 8px;
border: 1px solid #eee;
}
.menu-card p {
color: #555;
margin-bottom: 1rem;
}
.price {
font-weight: 600;
color: #4a2c20;
font-size: 1.25rem;
}
/* === ABOUT === */
.about {
background-color: #f5f0e8;
max-width: 100%;
padding: 6rem 2rem;
}
.about-content {
max-width: 800px;
margin: 0 auto;
text-align: center;
}
.about-content p {
margin: 0 auto 1.5rem auto;
}
/* === CONTACT === */
.contact-content {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 4rem;
margin-top: 2rem;
}
.contact-info p {
margin-bottom: 1.5rem;
}
.contact-form {
display: flex;
flex-direction: column;
gap: 1rem;
}
.contact-form input,
.contact-form textarea {
padding: 0.875rem 1rem;
border: 1px solid #ddd;
border-radius: 4px;
font-family: 'Inter', sans-serif;
font-size: 1rem;
}
/* === FOOTER === */
footer {
text-align: center;
padding: 2rem;
background-color: #1a1a1a;
color: #999;
font-size: 0.875rem;
}
Your layout is now structured and spacious. Next up, you will add hover interactions and transitions that make the site feel alive and responsive to the user.
Add Professional Interactions
Your site now has professional typography and a clean layout. But if you hover over a button or card, nothing happens. The page feels static.
Hover states and transitions are what make a site feel alive. They give visitors feedback that elements are interactive. In this step, you'll add smooth animations to buttons, cards, and form fields.
In this step, get ready to:
- Add smooth hover transitions to buttons.
- Add hover effects to menu cards.
- Style focus states for accessibility.
Add button hover states
CSS transitions animate property changes over time instead of switching instantly. A transition property on the base state tells the browser which properties to animate and how long the animation takes.
- In style.css, find the .btn rule.
- Find this line at the end of the rule:
cursor: pointer;
}
- Add the transition property above the closing brace, then add the .btn:hover rule below. Your buttons section should now look like this:
/* === BUTTONS === */
.btn {
display: inline-block;
padding: 0.875rem 2rem;
background-color: #c9a96e;
color: #1a1a1a;
text-decoration: none;
font-weight: 600;
font-size: 1rem;
border-radius: 4px;
border: none;
cursor: pointer;
transition: background-color 0.3s ease, transform 0.3s ease, box-shadow 0.3s ease;
}
.btn:hover {
background-color: #b8943d;
transform: translateY(-2px);
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
}
What does this code do?
The transition line tells the browser to animate three properties over 0.3 seconds whenever they change. The ease timing function starts fast and slows down at the end, which feels natural.
The :hover rule defines where those properties animate TO. The button darkens, lifts up 2 pixels, and gains a soft shadow underneath. All three changes happen simultaneously over 0.3 seconds.
- Save style.css and refresh your browser.
- Hover over the View Our Menu button in the hero section. You should see it darken and lift up slightly with a shadow appearing beneath it.
Button not animating on hover?
Make sure the transition line is inside the .btn rule (before the closing brace), not inside .btn:hover. The transition must be on the base state so the browser knows to animate when properties change.
Also check that .btn:hover appears after the .btn rule, not inside it.
Why isn't my button hover transition working?
Add card hover effects
The same transition technique works on cards. A subtle lift and shadow on hover tells visitors that cards are distinct, interactive elements.
- In style.css, find the .menu-card rule.
- Find this line at the end of the rule:
border: 1px solid #eee;
}
- Add the transition property above the closing brace, then add the .menu-card:hover rule below. Your updated menu card section should look like this:
.menu-card {
background: #ffffff;
padding: 2rem;
border-radius: 8px;
border: 1px solid #eee;
transition: transform 0.3s ease, box-shadow 0.3s ease;
}
.menu-card:hover {
transform: translateY(-4px);
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.08);
}
What does this code do?
On hover, each card lifts 4 pixels (double the button lift) and gains a larger, softer shadow. The bigger movement makes sense here because cards are larger elements. The shadow uses a very low opacity (0.08) so it feels subtle and natural.
- Save style.css and refresh your browser.
- Hover over any menu card in the Our Menu section. You should see the card lift up and a soft shadow appear beneath it.
Cards not lifting on hover?
Check that the transition line is inside .menu-card (not .menu-card:hover). Also make sure the rule name is exactly .menu-card:hover with no space before the colon.
Help me debug my menu card hover effect.
Style focus states for accessibility
Focus states show keyboard users which element is currently selected. Without them, someone tabbing through your site has no idea where they are. Professional sites style focus outlines to match their color palette instead of relying on the browser default.
- In style.css, add this .btn:focus rule directly below the .btn:hover rule you just added:
.btn:focus {
outline: 3px solid #c9a96e;
outline-offset: 3px;
}
What does this code do?
The outline property draws a ring around the button when it receives keyboard focus. The outline-offset pushes the ring 3 pixels away from the button edge so it doesn't look cramped. Using the same gold color (#c9a96e) as the button keeps everything visually consistent.
Now let's add focus styles to the contact form inputs. When a user clicks or tabs into a form field, the border should highlight to confirm they're in the right place.
- Find the .contact-form input, .contact-form textarea rule.
- Find this line at the end of the rule:
font-size: 1rem;
}
- Add the transition property above the closing brace, then add the focus rule below. Your updated contact form styles should look like this:
.contact-form input,
.contact-form textarea {
padding: 0.875rem 1rem;
border: 1px solid #ddd;
border-radius: 4px;
font-family: 'Inter', sans-serif;
font-size: 1rem;
transition: border-color 0.3s ease;
}
.contact-form input:focus,
.contact-form textarea:focus {
outline: none;
border-color: #c9a96e;
box-shadow: 0 0 0 3px rgba(201, 169, 110, 0.2);
}
What does this code do?
The transition: border-color 0.3s ease animates the border color change when a field receives focus. The :focus rule removes the default browser outline and replaces it with a gold border plus a soft glow effect using box-shadow.
The glow uses the same gold color at 20% opacity, creating a subtle halo that looks intentional and polished.
- Save style.css and refresh your browser.
- Scroll down to the contact form and click into the Your Name field. You should see the border turn gold with a soft glow around it.
- Press Tab on your keyboard a few times to move between form fields and buttons. Each element should highlight clearly as you tab through.
Not seeing the gold focus ring?
Make sure you clicked inside a form input (not just near it). If you see the browser's default blue outline instead, check that outline: none is inside your :focus rule. Also verify the rule selector matches exactly: .contact-form input:focus with no space before :focus.
Why isn't my custom focus style showing on form inputs?
✔️ Awesome, I've got everything!
Great. Double check you've saved style.css before moving on.
ⓧ I'd like to double check the full code
Here is the complete style.css file as it should look now:
/* === RESET & BASE === */
*, *::before, *::after {
margin: 0;
padding: 0;
box-sizing: border-box;
}
html {
scroll-behavior: smooth;
}
body {
font-family: 'Inter', sans-serif;
font-size: 1.125rem;
line-height: 1.7;
color: #2c2c2c;
background-color: #fdfbf7;
}
/* === TYPOGRAPHY === */
h1, h2, h3 {
font-family: 'Playfair Display', serif;
font-weight: 700;
line-height: 1.2;
color: #1a1a1a;
}
h1 {
font-size: 3.5rem;
letter-spacing: -0.02em;
}
h2 {
font-size: 2.5rem;
letter-spacing: -0.01em;
margin-bottom: 2rem;
text-align: center;
}
h3 {
font-size: 1.5rem;
margin-bottom: 0.5rem;
}
p {
max-width: 65ch;
}
/* === HERO === */
.hero {
min-height: 100vh;
display: flex;
align-items: center;
justify-content: center;
text-align: center;
padding: 2rem;
background: linear-gradient(135deg, #2c1810 0%, #4a2c20 100%);
color: #fdfbf7;
}
.hero h1 {
color: #fdfbf7;
margin-bottom: 1rem;
}
.hero-tagline {
font-size: 1.25rem;
opacity: 0.9;
margin-bottom: 2rem;
}
/* === BUTTONS === */
.btn {
display: inline-block;
padding: 0.875rem 2rem;
background-color: #c9a96e;
color: #1a1a1a;
text-decoration: none;
font-weight: 600;
font-size: 1rem;
border-radius: 4px;
border: none;
cursor: pointer;
transition: background-color 0.3s ease, transform 0.3s ease, box-shadow 0.3s ease;
}
.btn:hover {
background-color: #b8943d;
transform: translateY(-2px);
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
}
.btn:focus {
outline: 3px solid #c9a96e;
outline-offset: 3px;
}
/* === SECTIONS === */
.menu, .about, .contact {
padding: 6rem 2rem;
max-width: 1200px;
margin: 0 auto;
}
/* === MENU === */
.menu-grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 2rem;
margin-top: 2rem;
}
.menu-card {
background: #ffffff;
padding: 2rem;
border-radius: 8px;
border: 1px solid #eee;
transition: transform 0.3s ease, box-shadow 0.3s ease;
}
.menu-card:hover {
transform: translateY(-4px);
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.08);
}
.menu-card p {
color: #555;
margin-bottom: 1rem;
}
.price {
font-weight: 600;
color: #4a2c20;
font-size: 1.25rem;
}
/* === ABOUT === */
.about {
background-color: #f5f0e8;
max-width: 100%;
padding: 6rem 2rem;
}
.about-content {
max-width: 800px;
margin: 0 auto;
text-align: center;
}
.about-content p {
margin: 0 auto 1.5rem auto;
}
/* === CONTACT === */
.contact-content {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 4rem;
margin-top: 2rem;
}
.contact-info p {
margin-bottom: 1.5rem;
}
.contact-form {
display: flex;
flex-direction: column;
gap: 1rem;
}
.contact-form input,
.contact-form textarea {
padding: 0.875rem 1rem;
border: 1px solid #ddd;
border-radius: 4px;
font-family: 'Inter', sans-serif;
font-size: 1rem;
transition: border-color 0.3s ease;
}
.contact-form input:focus,
.contact-form textarea:focus {
outline: none;
border-color: #c9a96e;
box-shadow: 0 0 0 3px rgba(201, 169, 110, 0.2);
}
/* === FOOTER === */
footer {
text-align: center;
padding: 2rem;
background-color: #1a1a1a;
color: #999;
font-size: 0.875rem;
}
Your site now responds to every hover and click with smooth, intentional animations. Next up, you'll make sure all of this looks just as good on mobile screens.
Polish Mobile Responsiveness
Your site looks polished on a desktop-sized screen. But more than half of web visitors browse on their phone, and a three-column grid crammed onto a 375px screen is an instant bounce.
CSS media queries let you apply different styles based on screen width. In this step, you'll add a single breakpoint that adapts your typography, grids, and spacing for mobile devices.
In this step, get ready to:
- Reduce heading sizes for mobile screens.
- Switch multi-column grids to single columns.
- Verify the site looks clean at mobile widths.
Fix the mobile hero
Your h1 is set to 3.5rem. On a phone screen, that's massive and can overflow or look cramped against the edges.
The same problem hits your three-column menu grid and two-column contact layout. They need to collapse into a single column on narrow screens.
Add the mobile media query
- In style.css, scroll to the very bottom of the file (after the footer styles).
- Add the following responsive styles at the end of the file:
/* === RESPONSIVE === */
@media (max-width: 768px) {
h1 {
font-size: 2.5rem;
}
h2 {
font-size: 2rem;
}
.menu-grid {
grid-template-columns: 1fr;
}
.contact-content {
grid-template-columns: 1fr;
gap: 2rem;
}
.menu, .about, .contact {
padding: 4rem 1.5rem;
}
}
What does this code do?
The @media (max-width: 768px) wrapper means everything inside only applies when the browser window is 768 pixels wide or narrower (roughly tablet and phone sizes).
- h1 drops from 3.5rem to 2.5rem and h2 from 2.5rem to 2rem so headings don't dominate the small screen.
- .menu-grid switches to grid-template-columns: 1fr which stacks the cards in a single column.
- .contact-content also becomes single-column with a tighter 2rem gap between the info and form.
- Section padding drops from 6rem 2rem to 4rem 1.5rem so content doesn't float in too much whitespace on small devices.
- Save style.css.
Styles not changing?
- Make sure the @media block is placed after all your other styles. If it appears above the rules it overrides, the later rules will win.
- Check that the closing brace of the footer section is on its own line before your new comment. A missing brace from a previous section can swallow your media query.
Help me debug why my responsive styles aren't applying.
Test and refine
Responsive styles only activate below a certain width. You need to shrink your browser to see the changes take effect.
- Refresh your browser with index.html open.
- Drag the right edge of your browser window inward until the window is roughly phone-width (around 375px wide).
- Scroll through the entire page and confirm: the hero heading is smaller, menu cards stack vertically in one column, and the contact section shows the info above the form.
- Drag the window back wide to confirm the desktop layout returns to its multi-column state.
What should I see?
At narrow widths, the menu cards appear in a single vertical stack instead of three across. The contact info sits above the form instead of beside it. Headings look proportionate to the screen. Nothing overflows or requires horizontal scrolling.
Content overflowing off-screen?
- Check that your HTML file has the viewport meta tag. Look for the line that says meta name="viewport" in the head section. Without it, mobile browsers render the page at desktop width.
- Make sure there are no fixed pixel widths on containers. The max-width: 65ch on paragraphs is fine (it's a max, not a min), but a hard width: 1200px without max-width would cause overflow.
Help me fix horizontal overflow on mobile.
✔️ Awesome, I've got everything!
Great. Double check you've saved style.css before moving on.
ⓧ I'd like to double check the full code
Here is the complete style.css at this point:
/* === RESET & BASE === */
*, *::before, *::after {
margin: 0;
padding: 0;
box-sizing: border-box;
}
html {
scroll-behavior: smooth;
}
body {
font-family: 'Inter', sans-serif;
font-size: 1.125rem;
line-height: 1.7;
color: #2c2c2c;
background-color: #fdfbf7;
}
/* === TYPOGRAPHY === */
h1, h2, h3 {
font-family: 'Playfair Display', serif;
font-weight: 700;
line-height: 1.2;
color: #1a1a1a;
}
h1 {
font-size: 3.5rem;
letter-spacing: -0.02em;
}
h2 {
font-size: 2.5rem;
letter-spacing: -0.01em;
margin-bottom: 2rem;
text-align: center;
}
h3 {
font-size: 1.5rem;
margin-bottom: 0.5rem;
}
p {
max-width: 65ch;
}
/* === HERO === */
.hero {
min-height: 100vh;
display: flex;
align-items: center;
justify-content: center;
text-align: center;
padding: 2rem;
background: linear-gradient(135deg, #2c1810 0%, #4a2c20 100%);
color: #fdfbf7;
}
.hero h1 {
color: #fdfbf7;
margin-bottom: 1rem;
}
.hero-tagline {
font-size: 1.25rem;
opacity: 0.9;
margin-bottom: 2rem;
}
/* === BUTTONS === */
.btn {
display: inline-block;
padding: 0.875rem 2rem;
background-color: #c9a96e;
color: #1a1a1a;
text-decoration: none;
font-weight: 600;
font-size: 1rem;
border-radius: 4px;
border: none;
cursor: pointer;
transition: background-color 0.3s ease, transform 0.3s ease, box-shadow 0.3s ease;
}
.btn:hover {
background-color: #b8943d;
transform: translateY(-2px);
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
}
.btn:focus {
outline: 3px solid #c9a96e;
outline-offset: 3px;
}
/* === SECTIONS === */
.menu, .about, .contact {
padding: 6rem 2rem;
max-width: 1200px;
margin: 0 auto;
}
/* === MENU === */
.menu-grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 2rem;
margin-top: 2rem;
}
.menu-card {
background: #ffffff;
padding: 2rem;
border-radius: 8px;
border: 1px solid #eee;
transition: transform 0.3s ease, box-shadow 0.3s ease;
}
.menu-card:hover {
transform: translateY(-4px);
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.08);
}
.menu-card p {
color: #555;
margin-bottom: 1rem;
}
.price {
font-weight: 600;
color: #4a2c20;
font-size: 1.25rem;
}
/* === ABOUT === */
.about {
background-color: #f5f0e8;
max-width: 100%;
padding: 6rem 2rem;
}
.about-content {
max-width: 800px;
margin: 0 auto;
text-align: center;
}
.about-content p {
margin: 0 auto 1.5rem auto;
}
/* === CONTACT === */
.contact-content {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 4rem;
margin-top: 2rem;
}
.contact-info p {
margin-bottom: 1.5rem;
}
.contact-form {
display: flex;
flex-direction: column;
gap: 1rem;
}
.contact-form input,
.contact-form textarea {
padding: 0.875rem 1rem;
border: 1px solid #ddd;
border-radius: 4px;
font-family: 'Inter', sans-serif;
font-size: 1rem;
transition: border-color 0.3s ease;
}
.contact-form input:focus,
.contact-form textarea:focus {
outline: none;
border-color: #c9a96e;
box-shadow: 0 0 0 3px rgba(201, 169, 110, 0.2);
}
/* === FOOTER === */
footer {
text-align: center;
padding: 2rem;
background-color: #1a1a1a;
color: #999;
font-size: 0.875rem;
}
/* === RESPONSIVE === */
@media (max-width: 768px) {
h1 {
font-size: 2.5rem;
}
h2 {
font-size: 2rem;
}
.menu-grid {
grid-template-columns: 1fr;
}
.contact-content {
grid-template-columns: 1fr;
gap: 2rem;
}
.menu, .about, .contact {
padding: 4rem 1.5rem;
}
}
Your site now adapts gracefully from desktop to mobile. Next up, you'll deploy it live to the internet so anyone can see it.
Deploy Your Site Live
Your coffee shop site looks polished and professional on your own computer. The final step is making it available to the world.
You'll use Vercel, a hosting platform that deploys static HTML sites in seconds with no configuration needed. By the end of this step, you'll have a live URL you can share with anyone.
In this step, get ready to:
- Install the Vercel CLI and log into your account.
- Deploy your site with a single command.
- Verify your live URL in a browser and on your phone.
Install the Vercel CLI
The Vercel CLI is a command-line tool that lets you deploy websites directly from your terminal. You'll install it globally so you can use it from any project folder.
- Open your terminal in Cursor by pressing Ctrl+` (macOS and Windows).
- Install the Vercel CLI globally by running this command:
npm install -g vercel
What does this command do?
The -g flag installs the package globally on your system, meaning you can run vercel from any folder in your terminal. Without -g, it would only be available inside the current project.
- Wait for the installation to finish. You should see a success message with the installed version number.
Seeing a permissions error?
On macOS, you may need to prefix the command with sudo. On Windows, try closing your terminal and reopening it as an administrator.
help me fix a permissions error when installing the Vercel CLI globally with npm
Now you need to connect the CLI to a Vercel account. This is a free account that hosts your deployed sites.
- Log in to Vercel by running this command:
vercel login
What happens next?
This command opens your browser to Vercel's login page. If you don't have a Vercel account yet, you can create one for free using your email or GitHub account. Once you authorize the login, your terminal confirms the connection.
- Follow the prompts in your browser to sign in or create a free Vercel account.
- Return to your terminal. You should see a confirmation message that you are logged in.
Browser did not open?
If your browser did not open automatically, look in the terminal output for a URL. Copy and paste it into your browser manually to complete the login.
help me troubleshoot vercel login not opening my browser
Deploy your site
Your terminal should already be inside your coffee-shop-site folder because Cursor opened its terminal there. One command is all it takes to put your site on the internet.
- Deploy your site by running this command:
vercel
What prompts will I see?
The Vercel CLI asks a few setup questions the first time you deploy a project. Accept the defaults for each one by pressing Enter:
- "Set up and deploy?" - press Enter to confirm Yes.
- "Which scope do you want to deploy to?" - press Enter to select your personal account.
- "Link to existing project?" - press Enter for No.
- "What's your project's name?" - press Enter to accept the default folder name.
- "In which directory is your code located?" - press Enter to accept the current folder.
- "Want to override the settings?" - press Enter for No.
Vercel auto-detects that your project is static HTML with no build step needed. It uploads your files directly to its global CDN.
- Wait for the deployment to complete. It takes about 10-20 seconds.
- Look in the terminal output for a URL ending in .vercel.app. This is your live site.
Deployment failed?
Make sure your terminal is inside the coffee-shop-site folder. Run ls and confirm you see index.html and style.css listed. If not, use cd to navigate into the correct folder and try vercel again.
help me fix my Vercel deployment
Verify your live URL
Your site is now live on the internet. Time to confirm it works on real devices.
- Copy the .vercel.app URL from your terminal output.
- Open it in your browser. You should see your complete coffee shop site with all the typography, spacing, hover effects, and layout you polished in the previous steps.
- Open the same URL on your phone to verify the responsive layout works on a real mobile device.
Why check on a phone?
Resizing your browser window simulates mobile, but real phones can behave differently. Testing on an actual device catches font-size issues, touch-target problems, and viewport quirks that desktop testing misses.
You should see the hero section filling the screen, the menu cards stacking into a single column, and all text remaining readable without pinch-zooming.
Save this URL
This .vercel.app URL is your permanent shareable portfolio link. You can send it to potential clients, add it to your portfolio site, or include it on your resume. Vercel hosts it for free on their Hobby plan with no expiration.
Your polished coffee shop site is now live on the internet for anyone to see. This is the exact deliverable you would hand to a client. Next up, you can take it even further with the Secret Mission.
Secret mission
Add Smooth Scroll Navigation and Animated Reveals
Your polished coffee shop site looks great, but premium sites feel alive. Add a fixed navigation bar with smooth scroll anchors and CSS-only scroll-triggered animations that make sections fade in as you scroll down. No JavaScript required.
Clean Up Your Resources
Clean Up Your Resources
This project runs entirely locally and deploys to Vercel's free Hobby plan, so there are no ongoing costs. Decide whether to keep your resources running, pause them to come back later, or delete them entirely.
Resources you used:
- Local coffee-shop-site project folder on your Desktop.
- Vercel deployment (live .vercel.app URL).
- Vercel account (free Hobby plan).
Keep everything running
No action needed. Choose this if you're still actively building or want to keep your live site available as a portfolio piece.
- Your Vercel deployment stays live at its .vercel.app URL indefinitely on the free Hobby plan.
- Your local files remain in the coffee-shop-site folder on your Desktop.
- Node.js, the Vercel CLI, and Cursor stay installed on your machine for future projects.
Pause - I'll come back to this later
Shut down running processes to free up memory. Your files and deployment stay intact so you can pick up where you left off.
- Close Cursor if it is still open.
- Close any browser tabs showing your local preview.
- Your Vercel deployment continues to serve on its free URL with no action needed.
Delete - I don't want to use this again
Remove all project resources and start fresh. Follow each step below for a complete cleanup.
Delete your local project folder by running this command in Terminal:
macOS
rm -rf ~/Desktop/coffee-shop-site
Windows
Remove-Item -Recurse -Force ~\Desktop\coffee-shop-site
Delete your Vercel project and all its deployments. Navigate to your project folder first, then run:
vercel project rm
This removes the project from your Vercel account along with all associated deployments and the live URL. The CLI uses the linked project in the .vercel directory to identify which project to remove.
Alternatively, you can delete from the Vercel dashboard:
- Go to vercel.com/dashboard and select your coffee shop project.
- Click Settings in the sidebar.
- Scroll to the bottom of the General page and click Delete in the Delete Project section.
- Confirm by entering the project name, then click Continue.
To uninstall the Vercel CLI globally:
npm uninstall -g vercel
To uninstall Node.js:
- Windows: Open Settings, select Apps, then Apps & features. Find Node.js in the list and click Uninstall.
- macOS: The .pkg installer does not include an official uninstall command. You can leave Node.js installed for future projects, or search the Node.js GitHub wiki for manual removal steps.
To uninstall Cursor:
- macOS: Open Finder, go to Applications, and drag Cursor to the Trash.
- Windows: Open Settings, select Apps, then Apps & features. Find Cursor in the list and click Uninstall.
Nice Work!
Nice Work!
You just turned raw AI output into a professional, deployed website. That is the exact skill that makes freelance web design profitable.
You've learned how to:
- Built a polished multi-section business website with professional typography hierarchy, consistent spacing, and CSS Grid layouts.
- Added smooth hover interactions and CSS transitions that make the site feel alive and accessible.
- Deployed the finished site live on Vercel with a shareable URL you can send to clients.
- Secret Mission: Added a fixed navigation bar with smooth scroll anchors and CSS-only scroll-triggered animations using animation-timeline: view().
Ready to quiz yourself?