Align with AM stack SOPs: required files, nginx hardening, mobile CSS

- Add robots.txt, sitemap.xml (16 pages), 404.html, 500.html per SOP
- nginx: allow robots.txt/sitemap.xml explicitly, fix error_page to 404.html, deny _template.html, remove txt from deny list, fix API proxy comment
- Convert residential.png to residential.webp per image SOP
- components.css: mobile nav breakpoint 768→1023px, 360px ultra-narrow query, overflow-x:clip, inline grid collapse overrides
- blog/index.html: placeholder blog listing page with 3 article cards

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Concept Agent
2026-05-27 18:53:35 +02:00
parent 6917cb6701
commit 88ed4e6bda
8 changed files with 549 additions and 4 deletions
+90
View File
@@ -0,0 +1,90 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Page Not Found | Floor It Hardwood Floors</title>
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;600;800&display=swap" rel="stylesheet">
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
html, body {
height: 100%;
font-family: 'Inter', sans-serif;
background-color: #0c0805;
color: #f0e8da;
}
body {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
padding: 20px;
}
.container {
text-align: center;
max-width: 600px;
}
.error-code {
font-size: 120px;
font-weight: 800;
color: #c88b2a;
line-height: 1;
margin-bottom: 20px;
}
h1 {
font-size: 36px;
font-weight: 600;
margin-bottom: 20px;
}
p {
font-size: 16px;
font-weight: 400;
margin-bottom: 40px;
line-height: 1.6;
}
.button-group {
display: flex;
gap: 20px;
justify-content: center;
flex-wrap: wrap;
margin-bottom: 60px;
}
a.btn {
display: inline-block;
padding: 12px 30px;
background-color: #c88b2a;
color: #0c0805;
text-decoration: none;
font-weight: 600;
font-size: 14px;
border-radius: 4px;
transition: background-color 0.3s;
}
a.btn:hover {
background-color: #d99e3d;
}
.footer {
font-size: 14px;
color: #c88b2a;
}
</style>
</head>
<body>
<div class="container">
<div class="error-code">404</div>
<h1>Page Not Found</h1>
<p>The page you're looking for doesn't exist. Let us help you find what you need.</p>
<div class="button-group">
<a href="/" class="btn">Go to Homepage</a>
<a href="/contact/" class="btn">Contact Us</a>
</div>
<div class="footer">
<p>(716) 602-1429</p>
</div>
</div>
</body>
</html>
+90
View File
@@ -0,0 +1,90 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Server Error | Floor It Hardwood Floors</title>
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;600;800&display=swap" rel="stylesheet">
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
html, body {
height: 100%;
font-family: 'Inter', sans-serif;
background-color: #0c0805;
color: #f0e8da;
}
body {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
padding: 20px;
}
.container {
text-align: center;
max-width: 600px;
}
.error-code {
font-size: 120px;
font-weight: 800;
color: #c88b2a;
line-height: 1;
margin-bottom: 20px;
}
h1 {
font-size: 36px;
font-weight: 600;
margin-bottom: 20px;
}
p {
font-size: 16px;
font-weight: 400;
margin-bottom: 40px;
line-height: 1.6;
}
.button-group {
display: flex;
gap: 20px;
justify-content: center;
flex-wrap: wrap;
margin-bottom: 60px;
}
a.btn {
display: inline-block;
padding: 12px 30px;
background-color: #c88b2a;
color: #0c0805;
text-decoration: none;
font-weight: 600;
font-size: 14px;
border-radius: 4px;
transition: background-color 0.3s;
}
a.btn:hover {
background-color: #d99e3d;
}
.footer {
font-size: 14px;
color: #c88b2a;
}
</style>
</head>
<body>
<div class="container">
<div class="error-code">500</div>
<h1>Something Went Wrong</h1>
<p>We're experiencing a temporary issue. Please try again in a moment or contact us directly.</p>
<div class="button-group">
<a href="/" class="btn">Go to Homepage</a>
<a href="/contact/" class="btn">Contact Us</a>
</div>
<div class="footer">
<p>(716) 602-1429</p>
</div>
</div>
</body>
</html>
+144 -1
View File
@@ -1236,11 +1236,15 @@
.contact-layout { grid-template-columns: 1fr; }
}
@media (max-width: 768px) {
/* Header: switch to mobile menu earlier — desktop nav with logo + 6 links
+ phone + CTA needs ~1024px to fit without overflowing. */
@media (max-width: 1023px) {
.header-nav { display: none; }
.header-phone { display: none; }
.header-menu-btn { display: flex; }
}
@media (max-width: 768px) {
.hero-content { padding-block: var(--space-16); }
.process-steps { grid-template-columns: 1fr; }
@@ -1264,6 +1268,16 @@
.header-logo-sub { display: none; }
}
/* Ultra-narrow phones (iPhone SE portrait, 320px) — tighten header */
@media (max-width: 360px) {
.header-cta .btn--sm {
padding-inline: 0.75rem;
font-size: 0.75rem;
}
.header-logo img { height: 36px !important; }
.container { padding-inline: 0.875rem; }
}
/* --- Premium Elevation Pass ----------------------------- */
/* Hero: refined layout, larger stat section */
@@ -1651,3 +1665,132 @@
gap: var(--space-4);
align-items: flex-start;
}
/* ============================================================
Mobile responsive overrides — inline grids must collapse
to single column on narrow viewports. Inline styles win over
CSS unless we use !important inside media queries.
============================================================ */
/* Prevent off-screen positioned elements (mobile nav panel, etc.)
from creating horizontal scroll on the document. */
html, body {
overflow-x: clip;
max-width: 100%;
}
@media (max-width: 900px) {
/* Any inline 2-col grid pattern → single column */
[style*="grid-template-columns:1fr 1fr"],
[style*="grid-template-columns: 1fr 1fr"],
[style*="grid-template-columns:repeat(2,1fr)"],
[style*="grid-template-columns: repeat(2,1fr)"],
[style*="grid-template-columns:repeat(2, 1fr)"],
[style*="grid-template-columns: repeat(2, 1fr)"],
[style*="grid-template-columns:5fr 7fr"],
[style*="grid-template-columns: 5fr 7fr"] {
grid-template-columns: 1fr !important;
gap: 2rem !important;
}
/* Services 2x2 grid → single column */
.services-grid-2x2 {
grid-template-columns: 1fr !important;
}
/* Auto grids should stack tighter */
.grid--auto-3,
.grid--auto-4 {
grid-template-columns: 1fr !important;
gap: 1.5rem !important;
}
/* Order overrides — when 2-col uses order:1/2 to flip image/content,
reset on mobile so content always reads top-to-bottom */
[style*="order:1"],
[style*="order: 1"] {
order: 0 !important;
}
[style*="order:2"],
[style*="order: 2"] {
order: 0 !important;
}
/* Form rows stack */
.form-grid--2 {
grid-template-columns: 1fr !important;
}
/* Hero sub-stats stack with proper spacing */
.hero-trust {
flex-direction: column !important;
gap: 1.5rem !important;
align-items: flex-start !important;
}
/* Page hero padding tighten */
.page-hero {
padding-block: 4rem 3rem;
}
/* Section padding tighten */
.section {
padding-block: 3.5rem;
}
/* CTA strip vertical layout */
.cta-group {
flex-direction: column !important;
align-items: stretch !important;
}
.cta-group .btn {
width: 100%;
}
/* Form/contact layout — prevent intrinsic input width from blowing out
the grid track. Without min-width:0, <select> and <input> defaults push
the parent column wider than the viewport, causing horizontal scroll. */
.contact-layout { min-width: 0; }
.contact-form-wrap,
.contact-info-list { min-width: 0; max-width: 100%; }
.form-grid,
.form-grid--2 { min-width: 0; }
.form-field { min-width: 0; }
.form-field input,
.form-field textarea,
.form-field select {
min-width: 0;
max-width: 100%;
box-sizing: border-box;
}
}
@media (max-width: 600px) {
/* Tighten inline grid gaps further on phones */
[style*="grid-template-columns:1fr 1fr"],
[style*="grid-template-columns:repeat(2,1fr)"],
[style*="grid-template-columns: 1fr 1fr"],
[style*="grid-template-columns: repeat(2,1fr)"] {
gap: 1.5rem !important;
}
/* Auto-3 grid items single column */
.grid--auto-3 { gap: 1rem !important; }
/* Container side padding tighter */
.container {
padding-inline: 1rem;
}
/* Reduce all heading sizes a touch */
h1 { font-size: clamp(1.875rem, 8vw, 2.5rem) !important; }
h2 { font-size: clamp(1.5rem, 6vw, 2rem) !important; }
/* Page hero text tighter */
.page-hero h1 {
font-size: clamp(1.875rem, 7vw, 2.25rem) !important;
}
.lead {
font-size: 1rem;
}
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

+110
View File
@@ -0,0 +1,110 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="site-root" content="/">
<title>Hardwood Floor Tips & Guides | Floor It Blog</title>
<meta name="description" content="Expert hardwood floor care tips and guides for Buffalo, NY homeowners. Learn practical advice about floor maintenance, refinishing, and restoration from Floor It.">
<link rel="canonical" href="https://floorithardwoodfloors.com/blog/">
<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@300;400;500;600;700;800&display=swap" rel="stylesheet">
<link rel="stylesheet" href="/assets/css/main.css">
<link rel="stylesheet" href="/assets/css/components.css">
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "LocalBusiness",
"name": "Floor It Hardwood Floors",
"url": "https://floorithardwoodfloors.com",
"telephone": "+17166021429",
"email": "floorithardwoods@gmail.com",
"address": { "@type": "PostalAddress", "addressLocality": "Buffalo", "addressRegion": "NY", "addressCountry": "US" },
"areaServed": ["Buffalo", "Amherst", "Williamsville", "East Amherst", "Clarence", "Lancaster"],
"openingHours": "Mo-Sa 08:00-17:00",
"aggregateRating": { "@type": "AggregateRating", "ratingValue": "4.9", "reviewCount": "50" }
}
</script>
</head>
<body>
<div id="site-header"></div>
<main>
<section class="page-hero">
<div class="container page-hero-inner">
<nav class="breadcrumb" aria-label="Breadcrumb">
<a href="/">Home</a>
<span class="breadcrumb-sep">/</span>
<span>Blog</span>
</nav>
<span class="eyebrow">From the Floor It Team</span>
<h1>Hardwood Floor Tips & Guides</h1>
<p class="lead">Practical advice and expert tips for Buffalo, NY homeowners. Learn how to maintain, protect, and care for your hardwood floors with guidance from the Western New York refinishing specialists.</p>
</div>
</section>
<!-- ARTICLE CARDS -->
<section class="section section--light">
<div class="container">
<div class="section-header section-header--center">
<span class="eyebrow">Latest Articles</span>
<h2>Hardwood Floor Care Resources</h2>
</div>
<div class="grid grid--auto-3">
<div class="article-card" data-animate="up">
<div class="article-card-body">
<h3>How to Tell If Your Floors Need Refinishing</h3>
<p>Learn the warning signs that indicate your hardwood floors are ready for a professional refinish. From visible scratches to dull finishes, we explain what to look for and when to act.</p>
</div>
<div class="article-card-footer">
<a href="#" class="btn btn--primary btn--sm">Read More</a>
</div>
</div>
<div class="article-card" data-animate="up" data-delay="2">
<div class="article-card-body">
<h3>Hardwood vs. Engineered: Which Is Right for Your Home?</h3>
<p>Considering a new floor installation or replacement? Discover the pros and cons of solid hardwood and engineered hardwood to make the best choice for your Buffalo home.</p>
</div>
<div class="article-card-footer">
<a href="#" class="btn btn--primary btn--sm">Read More</a>
</div>
</div>
<div class="article-card" data-animate="up" data-delay="3">
<div class="article-card-body">
<h3>What to Expect During a Floor Refinishing Project</h3>
<p>Wondering what happens during a professional floor refinishing? Get a detailed walkthrough of the timeline, process, and what to expect from start to finish.</p>
</div>
<div class="article-card-footer">
<a href="#" class="btn btn--primary btn--sm">Read More</a>
</div>
</div>
</div>
</div>
</section>
<div class="cta-strip">
<div class="container">
<h2>Ready to Transform Your Floors?</h2>
<p>Request a free estimate and let Floor It help restore your hardwood floors to their original beauty.</p>
<div class="cta-group" style="justify-content:center;">
<a href="/contact/" class="btn btn--outline-dark btn--lg">Request an Estimate</a>
</div>
</div>
</div>
</main>
<div id="site-footer"></div>
<script src="/assets/js/components.js"></script>
<script src="/assets/js/main.js"></script>
</body>
</html>
+11 -3
View File
@@ -9,7 +9,7 @@ server {
deny all;
return 404;
}
location ~* \.(env|env\.example|conf|yml|yaml|py|pyc|md|txt|sh|sql|log|bak|old|swp|dockerfile)$ {
location ~* \.(env|env\.example|conf|yml|yaml|py|pyc|md|sh|sql|log|bak|old|swp|dockerfile)$ {
deny all;
return 404;
}
@@ -18,7 +18,15 @@ server {
return 404;
}
# API proxy — strip /api/ prefix, forward to Node.js service
location ~* /_template\.html$ {
deny all;
return 404;
}
location = /robots.txt { access_log off; }
location = /sitemap.xml { access_log off; }
# API proxy — strip /api/ prefix, forward to Python API service
location /api/ {
proxy_pass http://api:3001/;
proxy_http_version 1.1;
@@ -51,5 +59,5 @@ server {
gzip_types text/html text/css application/javascript image/svg+xml;
gzip_min_length 1024;
error_page 404 /index.html;
error_page 404 /404.html;
}
+5
View File
@@ -0,0 +1,5 @@
User-agent: *
Allow: /
Disallow: /api/
Sitemap: https://floorithardwoodfloors.com/sitemap.xml
+99
View File
@@ -0,0 +1,99 @@
<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
<url>
<loc>https://floorithardwoodfloors.com/</loc>
<lastmod>2026-05-27</lastmod>
<changefreq>weekly</changefreq>
<priority>1.0</priority>
</url>
<url>
<loc>https://floorithardwoodfloors.com/about/</loc>
<lastmod>2026-05-27</lastmod>
<changefreq>monthly</changefreq>
<priority>0.8</priority>
</url>
<url>
<loc>https://floorithardwoodfloors.com/contact/</loc>
<lastmod>2026-05-27</lastmod>
<changefreq>monthly</changefreq>
<priority>0.9</priority>
</url>
<url>
<loc>https://floorithardwoodfloors.com/reviews/</loc>
<lastmod>2026-05-27</lastmod>
<changefreq>weekly</changefreq>
<priority>0.8</priority>
</url>
<url>
<loc>https://floorithardwoodfloors.com/services/</loc>
<lastmod>2026-05-27</lastmod>
<changefreq>monthly</changefreq>
<priority>0.9</priority>
</url>
<url>
<loc>https://floorithardwoodfloors.com/services/floor-refinishing.html</loc>
<lastmod>2026-05-27</lastmod>
<changefreq>monthly</changefreq>
<priority>0.85</priority>
</url>
<url>
<loc>https://floorithardwoodfloors.com/services/floor-installation.html</loc>
<lastmod>2026-05-27</lastmod>
<changefreq>monthly</changefreq>
<priority>0.85</priority>
</url>
<url>
<loc>https://floorithardwoodfloors.com/services/floor-restoration.html</loc>
<lastmod>2026-05-27</lastmod>
<changefreq>monthly</changefreq>
<priority>0.85</priority>
</url>
<url>
<loc>https://floorithardwoodfloors.com/services/floor-sanding.html</loc>
<lastmod>2026-05-27</lastmod>
<changefreq>monthly</changefreq>
<priority>0.85</priority>
</url>
<url>
<loc>https://floorithardwoodfloors.com/locations/</loc>
<lastmod>2026-05-27</lastmod>
<changefreq>monthly</changefreq>
<priority>0.8</priority>
</url>
<url>
<loc>https://floorithardwoodfloors.com/locations/buffalo.html</loc>
<lastmod>2026-05-27</lastmod>
<changefreq>monthly</changefreq>
<priority>0.85</priority>
</url>
<url>
<loc>https://floorithardwoodfloors.com/locations/amherst.html</loc>
<lastmod>2026-05-27</lastmod>
<changefreq>monthly</changefreq>
<priority>0.8</priority>
</url>
<url>
<loc>https://floorithardwoodfloors.com/locations/williamsville.html</loc>
<lastmod>2026-05-27</lastmod>
<changefreq>monthly</changefreq>
<priority>0.8</priority>
</url>
<url>
<loc>https://floorithardwoodfloors.com/locations/east-amherst.html</loc>
<lastmod>2026-05-27</lastmod>
<changefreq>monthly</changefreq>
<priority>0.8</priority>
</url>
<url>
<loc>https://floorithardwoodfloors.com/locations/clarence.html</loc>
<lastmod>2026-05-27</lastmod>
<changefreq>monthly</changefreq>
<priority>0.8</priority>
</url>
<url>
<loc>https://floorithardwoodfloors.com/locations/lancaster.html</loc>
<lastmod>2026-05-27</lastmod>
<changefreq>monthly</changefreq>
<priority>0.8</priority>
</url>
</urlset>