Optimize: drop Bootstrap CDN, add caching headers & image hints #2
22
_headers
Normal file
22
_headers
Normal file
@@ -0,0 +1,22 @@
|
||||
# Cache-Control for static, stable-by-filename assets
|
||||
/img/*
|
||||
Cache-Control: public, max-age=2592000
|
||||
/favicon.svg
|
||||
Cache-Control: public, max-age=2592000
|
||||
/favicon-16.png
|
||||
Cache-Control: public, max-age=2592000
|
||||
/favicon-32.png
|
||||
Cache-Control: public, max-age=2592000
|
||||
/apple-touch-icon.png
|
||||
Cache-Control: public, max-age=2592000
|
||||
|
||||
# CSS/JS have no cache-busting hash yet; cache modestly
|
||||
/css/*
|
||||
Cache-Control: public, max-age=86400
|
||||
/js/*
|
||||
Cache-Control: public, max-age=86400
|
||||
|
||||
# Baseline security headers on every response
|
||||
/*
|
||||
X-Content-Type-Options: nosniff
|
||||
Referrer-Policy: strict-origin-when-cross-origin
|
||||
49
css/components/_grid.scss
Normal file
49
css/components/_grid.scss
Normal file
@@ -0,0 +1,49 @@
|
||||
// Minimal grid & utilities — self-hosted replacement for the small subset of
|
||||
// Bootstrap 4 this site used. Removes a render-blocking ~160 KB external
|
||||
// stylesheet. Breakpoint lg = 992px (one past $m-break: 991px).
|
||||
|
||||
.container {
|
||||
width: 100%;
|
||||
max-width: 1140px;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
padding-left: 15px;
|
||||
padding-right: 15px;
|
||||
}
|
||||
|
||||
.row {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
margin-left: -15px;
|
||||
margin-right: -15px;
|
||||
|
||||
> [class*="col-"] {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
padding-left: 15px;
|
||||
padding-right: 15px;
|
||||
}
|
||||
}
|
||||
|
||||
// mobile-first: columns are full width until the lg breakpoint
|
||||
[class*="col-lg-"] { flex: 0 0 100%; max-width: 100%; }
|
||||
|
||||
.align-items-center { align-items: center; }
|
||||
.text-center { text-align: center; }
|
||||
.mb-4 { margin-bottom: 1.5rem; }
|
||||
|
||||
.table-responsive {
|
||||
display: block;
|
||||
width: 100%;
|
||||
overflow-x: auto;
|
||||
-webkit-overflow-scrolling: touch;
|
||||
}
|
||||
|
||||
@media (min-width: 992px) {
|
||||
.col-lg-5 { flex: 0 0 41.6667%; max-width: 41.6667%; }
|
||||
.col-lg-6 { flex: 0 0 50%; max-width: 50%; }
|
||||
.col-lg-7 { flex: 0 0 58.3333%; max-width: 58.3333%; }
|
||||
.order-lg-1 { order: 1; }
|
||||
.order-lg-2 { order: 2; }
|
||||
.mb-lg-0 { margin-bottom: 0; }
|
||||
}
|
||||
72
css/main.css
72
css/main.css
@@ -34,9 +34,71 @@ html { scroll-behavior: smooth; }
|
||||
p, a, li, span, div, td, th { font-family: "Lato", sans-serif; }
|
||||
h1, h2, h3, h4, h5, h6 { font-family: "Libre Baskerville", serif; }
|
||||
|
||||
img { max-width: 100%; }
|
||||
img { max-width: 100%; vertical-align: middle; }
|
||||
h1, h2, h3, h4, h5, h6 { margin-top: 0; }
|
||||
p { margin-top: 0; margin-bottom: 1rem; }
|
||||
|
||||
/* ============================================================
|
||||
MINIMAL GRID & UTILITIES
|
||||
Self-hosted replacement for the small subset of Bootstrap 4
|
||||
this site used (grid, a few utilities, button base). Removes a
|
||||
render-blocking ~160 KB external stylesheet. Breakpoint lg = 992px.
|
||||
============================================================ */
|
||||
.container {
|
||||
width: 100%;
|
||||
max-width: 1140px;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
padding-left: 15px;
|
||||
padding-right: 15px;
|
||||
}
|
||||
.row {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
margin-left: -15px;
|
||||
margin-right: -15px;
|
||||
}
|
||||
.row > [class*="col-"] {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
padding-left: 15px;
|
||||
padding-right: 15px;
|
||||
}
|
||||
/* mobile-first: columns are full width until the lg breakpoint */
|
||||
[class*="col-lg-"] { flex: 0 0 100%; max-width: 100%; }
|
||||
|
||||
.align-items-center { align-items: center; }
|
||||
.text-center { text-align: center; }
|
||||
|
||||
.mb-4 { margin-bottom: 1.5rem; }
|
||||
|
||||
.table-responsive {
|
||||
display: block;
|
||||
width: 100%;
|
||||
overflow-x: auto;
|
||||
-webkit-overflow-scrolling: touch;
|
||||
}
|
||||
|
||||
@media (min-width: 992px) {
|
||||
.col-lg-5 { flex: 0 0 41.6667%; max-width: 41.6667%; }
|
||||
.col-lg-6 { flex: 0 0 50%; max-width: 50%; }
|
||||
.col-lg-7 { flex: 0 0 58.3333%; max-width: 58.3333%; }
|
||||
.order-lg-1 { order: 1; }
|
||||
.order-lg-2 { order: 2; }
|
||||
.mb-lg-0 { margin-bottom: 0; }
|
||||
}
|
||||
|
||||
/* ---------- Buttons ---------- */
|
||||
.btn {
|
||||
display: inline-block;
|
||||
vertical-align: middle;
|
||||
text-align: center;
|
||||
border: 1px solid transparent;
|
||||
line-height: 1.5;
|
||||
cursor: pointer;
|
||||
text-decoration: none;
|
||||
user-select: none;
|
||||
}
|
||||
.btn {
|
||||
font-family: "Libre Baskerville", serif;
|
||||
font-size: 14px;
|
||||
@@ -46,10 +108,18 @@ img { max-width: 100%; }
|
||||
}
|
||||
.btn + .btn { margin-left: 0.5rem; }
|
||||
|
||||
.btn-light {
|
||||
color: #212529;
|
||||
background-color: #f8f9fa;
|
||||
border-color: #f8f9fa;
|
||||
}
|
||||
|
||||
.btn-primary {
|
||||
color: var(--white);
|
||||
background-color: var(--gold);
|
||||
border-color: var(--gold);
|
||||
}
|
||||
.btn-primary:hover { color: var(--white); }
|
||||
.btn-primary:hover {
|
||||
background-color: var(--gold-dark);
|
||||
border-color: var(--gold-dark);
|
||||
|
||||
@@ -22,9 +22,19 @@ $l-break: 1199px;
|
||||
|
||||
* { box-sizing: border-box; }
|
||||
|
||||
@import 'components/grid';
|
||||
|
||||
//btns
|
||||
.btn {
|
||||
@include Libre;
|
||||
display: inline-block;
|
||||
vertical-align: middle;
|
||||
text-align: center;
|
||||
border: 1px solid transparent;
|
||||
line-height: 1.5;
|
||||
cursor: pointer;
|
||||
text-decoration: none;
|
||||
user-select: none;
|
||||
font-size: 14px;
|
||||
letter-spacing: 0.3px;
|
||||
padding: 0.55rem 1.5rem;
|
||||
@@ -33,10 +43,19 @@ $l-break: 1199px;
|
||||
& + .btn { margin-left: 0.5rem; }
|
||||
}
|
||||
|
||||
.btn-light {
|
||||
color: #212529;
|
||||
background-color: #f8f9fa;
|
||||
border-color: #f8f9fa;
|
||||
}
|
||||
|
||||
.btn-primary {
|
||||
color: $white;
|
||||
background-color: $gold;
|
||||
border-color: $gold;
|
||||
|
||||
&:hover { color: $white; }
|
||||
|
||||
&:hover {
|
||||
background-color: darken($gold, 10%);
|
||||
border-color: darken($gold, 10%);
|
||||
@@ -73,9 +92,12 @@ p, a, li, span, div, td, th {
|
||||
|
||||
h1, h2, h3, h4, h5, h6 {
|
||||
@include Libre;
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
img { max-width: 100%; }
|
||||
p { margin-top: 0; margin-bottom: 1rem; }
|
||||
|
||||
img { max-width: 100%; vertical-align: middle; }
|
||||
|
||||
.page-content {
|
||||
padding-top: 92px;
|
||||
|
||||
48
index.html
48
index.html
@@ -19,8 +19,6 @@
|
||||
<link rel="apple-touch-icon" href="apple-touch-icon.png">
|
||||
<meta name="theme-color" content="#231F20">
|
||||
|
||||
<!-- Bootstrap grid/utilities -->
|
||||
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css" integrity="sha384-Vkoo8x4CGsO3+Hhxv8T/Q5PaXtkKtu6ug5TOeNV6gBiFeWPGFN9MuhOf23Q9Ifjh" crossorigin="anonymous">
|
||||
<!-- Fonts -->
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||
@@ -87,7 +85,7 @@
|
||||
<p>Create lifelong memories with your family in a luxury, custom home within a secure and quiet community. Welcome home to Pine Creek.</p>
|
||||
</div>
|
||||
<div class="col-lg-6">
|
||||
<img class="feature-img" src="img/gallery/IMG_1964.jpg" alt="A stately custom stone home in Pine Creek" loading="lazy">
|
||||
<img class="feature-img" src="img/gallery/IMG_1964.jpg" alt="A stately custom stone home in Pine Creek" loading="lazy" decoding="async">
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
@@ -106,9 +104,9 @@
|
||||
<div class="col-lg-7">
|
||||
<div class="gallery" data-gallery="vineyard" aria-roledescription="carousel">
|
||||
<div class="gallery-track">
|
||||
<img class="gallery-img is-active" src="img/gallery/IMG_1937.jpg" alt="Tuscan-style Vineyard home with terracotta tile roof" loading="lazy">
|
||||
<img class="gallery-img" src="img/gallery/IMG_1941.jpg" alt="Mediterranean-style Vineyard home with terracotta tile roof" loading="lazy">
|
||||
<img class="gallery-img" src="img/gallery/IMG_1943.jpg" alt="Spanish-Tuscan Vineyard estate with stucco and stone" loading="lazy">
|
||||
<img class="gallery-img is-active" src="img/gallery/IMG_1937.jpg" alt="Tuscan-style Vineyard home with terracotta tile roof" loading="lazy" decoding="async">
|
||||
<img class="gallery-img" src="img/gallery/IMG_1941.jpg" alt="Mediterranean-style Vineyard home with terracotta tile roof" loading="lazy" decoding="async">
|
||||
<img class="gallery-img" src="img/gallery/IMG_1943.jpg" alt="Spanish-Tuscan Vineyard estate with stucco and stone" loading="lazy" decoding="async">
|
||||
</div>
|
||||
<button class="gallery-arrow prev" aria-label="Previous image">
|
||||
<svg viewBox="0 0 24 24" stroke="currentColor" stroke-width="2" fill="none" stroke-linecap="round" stroke-linejoin="round"><polyline points="15 18 9 12 15 6"></polyline></svg>
|
||||
@@ -138,16 +136,16 @@
|
||||
<div class="col-lg-7 order-lg-1">
|
||||
<div class="gallery" data-gallery="estate" aria-roledescription="carousel">
|
||||
<div class="gallery-track">
|
||||
<img class="gallery-img is-active" src="img/gallery/IMG_1947.jpg" alt="Brick and stone French country estate" loading="lazy">
|
||||
<img class="gallery-img" src="img/gallery/IMG_1922.jpg" alt="Stately brick custom home on a manicured lawn" loading="lazy">
|
||||
<img class="gallery-img" src="img/gallery/IMG_1945.jpg" alt="Stone custom home with circular drive" loading="lazy">
|
||||
<img class="gallery-img" src="img/gallery/IMG_1971.jpg" alt="French country home with stone accents" loading="lazy">
|
||||
<img class="gallery-img" src="img/gallery/IMG_1977.jpg" alt="Brick and stone estate with mature landscaping" loading="lazy">
|
||||
<img class="gallery-img" src="img/gallery/IMG_2978.jpg" alt="Custom estate framed by trees" loading="lazy">
|
||||
<img class="gallery-img" src="img/gallery/IMG_1985.jpg" alt="Stone manor home at dusk" loading="lazy">
|
||||
<img class="gallery-img" src="img/gallery/IMG_1955.jpg" alt="Stone and stucco custom home with circular drive" loading="lazy">
|
||||
<img class="gallery-img" src="img/gallery/IMG_1980.jpg" alt="Sprawling brick and stone estate" loading="lazy">
|
||||
<img class="gallery-img" src="img/gallery/IMG_1914.jpg" alt="Brick estate with formal fountain garden" loading="lazy">
|
||||
<img class="gallery-img is-active" src="img/gallery/IMG_1947.jpg" alt="Brick and stone French country estate" loading="lazy" decoding="async">
|
||||
<img class="gallery-img" src="img/gallery/IMG_1922.jpg" alt="Stately brick custom home on a manicured lawn" loading="lazy" decoding="async">
|
||||
<img class="gallery-img" src="img/gallery/IMG_1945.jpg" alt="Stone custom home with circular drive" loading="lazy" decoding="async">
|
||||
<img class="gallery-img" src="img/gallery/IMG_1971.jpg" alt="French country home with stone accents" loading="lazy" decoding="async">
|
||||
<img class="gallery-img" src="img/gallery/IMG_1977.jpg" alt="Brick and stone estate with mature landscaping" loading="lazy" decoding="async">
|
||||
<img class="gallery-img" src="img/gallery/IMG_2978.jpg" alt="Custom estate framed by trees" loading="lazy" decoding="async">
|
||||
<img class="gallery-img" src="img/gallery/IMG_1985.jpg" alt="Stone manor home at dusk" loading="lazy" decoding="async">
|
||||
<img class="gallery-img" src="img/gallery/IMG_1955.jpg" alt="Stone and stucco custom home with circular drive" loading="lazy" decoding="async">
|
||||
<img class="gallery-img" src="img/gallery/IMG_1980.jpg" alt="Sprawling brick and stone estate" loading="lazy" decoding="async">
|
||||
<img class="gallery-img" src="img/gallery/IMG_1914.jpg" alt="Brick estate with formal fountain garden" loading="lazy" decoding="async">
|
||||
</div>
|
||||
<button class="gallery-arrow prev" aria-label="Previous image">
|
||||
<svg viewBox="0 0 24 24" stroke="currentColor" stroke-width="2" fill="none" stroke-linecap="round" stroke-linejoin="round"><polyline points="15 18 9 12 15 6"></polyline></svg>
|
||||
@@ -175,12 +173,12 @@
|
||||
<div class="col-lg-7">
|
||||
<div class="gallery" data-gallery="community" aria-roledescription="carousel">
|
||||
<div class="gallery-track">
|
||||
<img class="gallery-img is-active" src="img/community/community-pavilion-pond.jpg" alt="Lakeside pavilion overlooking the community pond and fountain" loading="lazy">
|
||||
<img class="gallery-img" src="img/community/community-pavilion.jpg" alt="Aerial view of the community pavilion and gardens" loading="lazy">
|
||||
<img class="gallery-img" src="img/community/community-vineyard-gate.jpg" alt="The Vineyard entrance monument with stone cupola" loading="lazy">
|
||||
<img class="gallery-img" src="img/community/community-vineyard-rows.jpg" alt="Manicured vineyard rows lining a community street" loading="lazy">
|
||||
<img class="gallery-img" src="img/community/community-aerial.jpg" alt="Aerial view of Pine Creek's tree-lined streets and estates" loading="lazy">
|
||||
<img class="gallery-img" src="img/community/community-forest-pond.jpg" alt="Pine Creek homes nestled among the woods near the pond" loading="lazy">
|
||||
<img class="gallery-img is-active" src="img/community/community-pavilion-pond.jpg" alt="Lakeside pavilion overlooking the community pond and fountain" loading="lazy" decoding="async">
|
||||
<img class="gallery-img" src="img/community/community-pavilion.jpg" alt="Aerial view of the community pavilion and gardens" loading="lazy" decoding="async">
|
||||
<img class="gallery-img" src="img/community/community-vineyard-gate.jpg" alt="The Vineyard entrance monument with stone cupola" loading="lazy" decoding="async">
|
||||
<img class="gallery-img" src="img/community/community-vineyard-rows.jpg" alt="Manicured vineyard rows lining a community street" loading="lazy" decoding="async">
|
||||
<img class="gallery-img" src="img/community/community-aerial.jpg" alt="Aerial view of Pine Creek's tree-lined streets and estates" loading="lazy" decoding="async">
|
||||
<img class="gallery-img" src="img/community/community-forest-pond.jpg" alt="Pine Creek homes nestled among the woods near the pond" loading="lazy" decoding="async">
|
||||
</div>
|
||||
<button class="gallery-arrow prev" aria-label="Previous image">
|
||||
<svg viewBox="0 0 24 24" stroke="currentColor" stroke-width="2" fill="none" stroke-linecap="round" stroke-linejoin="round"><polyline points="15 18 9 12 15 6"></polyline></svg>
|
||||
@@ -204,7 +202,7 @@
|
||||
<p class="section-lead">Winding, tree-lined streets — Tuscany Drive, Chardonnay Circle, Willowood Road, Stone Ridge Road, Richwood Circle, and Rolling Ridge Drive — thread through Pine Creek's gently rolling, one-acre-plus homesites.</p>
|
||||
</div>
|
||||
<div class="map-frame">
|
||||
<img class="map-img" src="img/community-map.jpg" alt="Map of the Pine Creek community streets" loading="lazy">
|
||||
<img class="map-img" src="img/community-map.jpg" alt="Map of the Pine Creek community streets" loading="lazy" decoding="async">
|
||||
</div>
|
||||
</section>
|
||||
|
||||
@@ -220,14 +218,14 @@
|
||||
<p>The town is conveniently located right off I-85, within 30 minutes of uptown Charlotte and Charlotte Douglas International Airport. With growing businesses, a vast array of shops and restaurants, a beautiful downtown, sought-after Cabarrus County and private schools, and the grandeur of the NC Research Campus, Kannapolis is a wonderful place to call home.</p>
|
||||
</div>
|
||||
<div class="col-lg-6">
|
||||
<img class="feature-img" src="img/kannapolis-nc.jpg" alt="Downtown Kannapolis, North Carolina" loading="lazy">
|
||||
<img class="feature-img" src="img/kannapolis-nc.jpg" alt="Downtown Kannapolis, North Carolina" loading="lazy" decoding="async">
|
||||
</div>
|
||||
</div>
|
||||
<div class="map-embed">
|
||||
<iframe
|
||||
title="Map of Pine Creek in Kannapolis, North Carolina"
|
||||
src="https://www.google.com/maps?q=Tuscany%20Dr%2C%20Kannapolis%2C%20NC%2028081&z=15&output=embed"
|
||||
loading="lazy" referrerpolicy="no-referrer-when-downgrade" allowfullscreen></iframe>
|
||||
loading="lazy" decoding="async" referrerpolicy="no-referrer-when-downgrade" allowfullscreen></iframe>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user