Back to CSS Number Counter Animations Art Deco Real Estate CSS + JS
Share
HTML
<div class="cnc-deco">
  <div class="cnc-deco-frame">
    <div class="cnc-deco-frame-inner">
      <div class="cnc-deco-corner cnc-deco-tl"></div>
      <div class="cnc-deco-corner cnc-deco-tr"></div>
      <div class="cnc-deco-corner cnc-deco-bl"></div>
      <div class="cnc-deco-corner cnc-deco-br"></div>
      <div class="cnc-deco-eyebrow">Q1 2026 · Market Intelligence Report</div>
      <h2 class="cnc-deco-section-title">Luxury Real Estate <em>Portfolio</em></h2>
      <div class="cnc-deco-ornament"><span class="cnc-deco-ornament-icon">◆ ◆ ◆</span></div>
      <div class="cnc-deco-stats-row">
        <div class="cnc-deco-stat">
          <span class="cnc-deco-stat-pre">Portfolio</span>
          <div class="cnc-deco-stat-num">
            <span class="cnc-deco-stat-sym">$</span>
            <span class="cnc-num" data-target="4.2" data-decimals="1">0</span>
            <span class="cnc-deco-stat-suf">B</span>
          </div>
          <span class="cnc-deco-stat-label">Total Value</span>
        </div>
        <div class="cnc-deco-divider-v"></div>
        <div class="cnc-deco-stat">
          <span class="cnc-deco-stat-pre">Properties</span>
          <div class="cnc-deco-stat-num">
            <span class="cnc-num" data-target="214">0</span>
          </div>
          <span class="cnc-deco-stat-label">Active Listings</span>
        </div>
        <div class="cnc-deco-divider-v"></div>
        <div class="cnc-deco-stat">
          <span class="cnc-deco-stat-pre">Avg. Price</span>
          <div class="cnc-deco-stat-num">
            <span class="cnc-deco-stat-sym">$</span>
            <span class="cnc-num" data-target="8.7" data-decimals="1">0</span>
            <span class="cnc-deco-stat-suf">M</span>
          </div>
          <span class="cnc-deco-stat-label">Per Property</span>
        </div>
        <div class="cnc-deco-divider-v"></div>
        <div class="cnc-deco-stat">
          <span class="cnc-deco-stat-pre">Return</span>
          <div class="cnc-deco-stat-num">
            <span class="cnc-num" data-target="23.4" data-decimals="1">0</span>
            <span class="cnc-deco-stat-suf">%</span>
          </div>
          <span class="cnc-deco-stat-label">Annualized</span>
        </div>
      </div>
      <div class="cnc-deco-ornament"><span class="cnc-deco-ornament-icon">◆ ✦ ◆</span></div>
      <div class="cnc-deco-prop-grid">
        <div class="cnc-deco-prop-card">
          <div class="cnc-deco-ring-mini">
            <svg width="44" height="44" viewBox="0 0 44 44">
              <circle class="cnc-deco-rb" cx="22" cy="22" r="18"/>
              <circle class="cnc-deco-rf" cx="22" cy="22" r="18" data-pct="85"/>
            </svg>
          </div>
          <span class="cnc-deco-prop-icon">Residential</span>
          <div class="cnc-deco-prop-num-wrap">
            <span class="cnc-deco-prop-num cnc-num" data-target="127">0</span>
          </div>
          <div class="cnc-deco-prop-bar"><div class="cnc-deco-prop-bar-fill"></div></div>
          <span class="cnc-deco-prop-sublabel">Units Occupied</span>
          <span class="cnc-deco-tag">Prime</span>
        </div>
        <div class="cnc-deco-prop-card">
          <div class="cnc-deco-ring-mini">
            <svg width="44" height="44" viewBox="0 0 44 44">
              <circle class="cnc-deco-rb" cx="22" cy="22" r="18"/>
              <circle class="cnc-deco-rf" cx="22" cy="22" r="18" data-pct="62"/>
            </svg>
          </div>
          <span class="cnc-deco-prop-icon">Commercial</span>
          <div class="cnc-deco-prop-num-wrap">
            <span class="cnc-deco-prop-num cnc-num" data-target="53">0</span>
          </div>
          <div class="cnc-deco-prop-bar"><div class="cnc-deco-prop-bar-fill"></div></div>
          <span class="cnc-deco-prop-sublabel">Active Leases</span>
          <span class="cnc-deco-tag">Trophy</span>
        </div>
        <div class="cnc-deco-prop-card">
          <div class="cnc-deco-ring-mini">
            <svg width="44" height="44" viewBox="0 0 44 44">
              <circle class="cnc-deco-rb" cx="22" cy="22" r="18"/>
              <circle class="cnc-deco-rf" cx="22" cy="22" r="18" data-pct="91"/>
            </svg>
          </div>
          <span class="cnc-deco-prop-icon">Hospitality</span>
          <div class="cnc-deco-prop-num-wrap">
            <span class="cnc-deco-prop-num cnc-num" data-target="34">0</span>
          </div>
          <div class="cnc-deco-prop-bar"><div class="cnc-deco-prop-bar-fill"></div></div>
          <span class="cnc-deco-prop-sublabel">Keys Managed</span>
          <span class="cnc-deco-tag">Ultra-Lux</span>
        </div>
      </div>
    </div>
  </div>
</div>
CSS
.cnc-deco {
  --deco-gold: #c9a84c;
  --deco-gold-light: #e8c96b;
  --deco-cream: #faf6ee;
  --deco-dark: #1a1510;
  --deco-ink: #2c2318;
  position: relative;
  display: flex; align-items: center; justify-content: center;
  padding: 60px 24px;
  background: var(--deco-cream);
  background-image:
    radial-gradient(ellipse at top, #ede5d0 0%, transparent 60%),
    repeating-linear-gradient(45deg,
      transparent, transparent 20px,
      rgba(201,168,76,0.04) 20px, rgba(201,168,76,0.04) 21px);
  font-family: 'Josefin Sans', sans-serif;
  color: var(--deco-ink);
}
.cnc-deco-frame {
  width: 900px;
  border: 1px solid var(--deco-gold);
  padding: 3px; position: relative;
}
.cnc-deco-frame-inner {
  border: 1px solid rgba(201,168,76,0.4);
  padding: 48px 52px; position: relative;
}
.cnc-deco-corner {
  position: absolute; width: 40px; height: 40px;
  border-color: var(--deco-gold); border-style: solid;
}
.cnc-deco-tl { top: 10px; left: 10px; border-width: 2px 0 0 2px; }
.cnc-deco-tr { top: 10px; right: 10px; border-width: 2px 2px 0 0; }
.cnc-deco-bl { bottom: 10px; left: 10px; border-width: 0 0 2px 2px; }
.cnc-deco-br { bottom: 10px; right: 10px; border-width: 0 2px 2px 0; }
.cnc-deco-ornament {
  display: flex; align-items: center; gap: 16px;
  margin: 36px 0; color: var(--deco-gold);
}
.cnc-deco-ornament::before, .cnc-deco-ornament::after {
  content: ''; flex: 1; height: 1px;
  background: linear-gradient(90deg, transparent, var(--deco-gold), transparent);
}
.cnc-deco-ornament-icon { font-size: 18px; letter-spacing: 8px; }
.cnc-deco-eyebrow {
  font-size: 9px; letter-spacing: 6px; text-transform: uppercase;
  color: var(--deco-gold); text-align: center;
  margin-bottom: 8px; font-weight: 300;
}
.cnc-deco-section-title {
  font-family: 'Playfair Display', serif;
  font-size: clamp(28px, 4vw, 44px); font-weight: 400;
  text-align: center; color: var(--deco-dark);
  letter-spacing: -0.5px; margin: 0 0 4px;
}
.cnc-deco-section-title em { font-style: italic; color: var(--deco-gold); }
.cnc-deco-stats-row {
  display: grid;
  grid-template-columns: 1fr auto 1fr auto 1fr auto 1fr;
  align-items: center; gap: 0; margin-top: 8px;
}
.cnc-deco-divider-v {
  width: 1px; height: 80px;
  background: linear-gradient(180deg, transparent, var(--deco-gold), transparent);
  margin: auto;
}
.cnc-deco-stat {
  text-align: center; padding: 24px 12px;
  opacity: 0; transform: translateY(16px);
  animation: cnc-deco-statIn 0.8s ease forwards;
}
.cnc-deco-stat:nth-child(1) { animation-delay: 0.2s; }
.cnc-deco-stat:nth-child(3) { animation-delay: 0.4s; }
.cnc-deco-stat:nth-child(5) { animation-delay: 0.6s; }
.cnc-deco-stat:nth-child(7) { animation-delay: 0.8s; }
@keyframes cnc-deco-statIn { to { opacity: 1; transform: translateY(0); } }
.cnc-deco-stat-pre {
  font-size: 11px; letter-spacing: 4px; text-transform: uppercase;
  color: var(--deco-gold); font-weight: 100;
  margin-bottom: 8px; display: block;
}
.cnc-deco-stat-num {
  font-family: 'Playfair Display', serif;
  font-size: clamp(36px, 5vw, 58px); font-weight: 700;
  color: var(--deco-dark); line-height: 1; letter-spacing: -1px;
  display: flex; justify-content: center; align-items: baseline; gap: 3px;
}
.cnc-deco-stat-sym {
  font-family: 'Josefin Sans', sans-serif;
  font-size: 0.4em; font-weight: 100; letter-spacing: 2px;
  color: var(--deco-gold); align-self: flex-start; margin-top: 6px;
}
.cnc-deco-stat-suf {
  font-size: 0.35em; font-weight: 100;
  color: var(--deco-gold); letter-spacing: 2px;
}
.cnc-deco-stat-label {
  font-size: 9px; letter-spacing: 4px; text-transform: uppercase;
  color: rgba(44,35,24,0.4); font-weight: 300;
  margin-top: 8px; display: block;
}
.cnc-deco-prop-grid {
  display: grid; grid-template-columns: repeat(3, 1fr);
  gap: 24px; margin-top: 8px;
}
.cnc-deco-prop-card {
  border: 1px solid rgba(201,168,76,0.25);
  padding: 28px 24px; position: relative; overflow: hidden;
  transition: border-color 0.3s, box-shadow 0.3s;
  opacity: 0; animation: cnc-deco-statIn 0.8s ease forwards;
}
.cnc-deco-prop-card:nth-child(1) { animation-delay: 0.3s; }
.cnc-deco-prop-card:nth-child(2) { animation-delay: 0.5s; }
.cnc-deco-prop-card:nth-child(3) { animation-delay: 0.7s; }
.cnc-deco-prop-card::after {
  content: ''; position: absolute;
  bottom: 0; left: 0; right: 0; height: 2px;
  background: linear-gradient(90deg, var(--deco-gold), var(--deco-gold-light), var(--deco-gold));
  transform: scaleX(0); transition: transform 0.4s ease;
}
.cnc-deco-prop-card:hover {
  border-color: var(--deco-gold);
  box-shadow: 0 8px 40px rgba(201,168,76,0.1);
}
.cnc-deco-prop-card:hover::after { transform: scaleX(1); }
.cnc-deco-prop-icon {
  font-size: 10px; letter-spacing: 5px; text-transform: uppercase;
  color: var(--deco-gold); font-weight: 100;
  margin-bottom: 20px; display: block;
}
.cnc-deco-prop-num {
  font-family: 'Playfair Display', serif;
  font-size: clamp(38px, 5vw, 54px); font-weight: 700;
  color: var(--deco-dark); line-height: 1; letter-spacing: -1px;
}
.cnc-deco-prop-num-wrap {
  display: flex; align-items: baseline; gap: 4px; margin-bottom: 10px;
}
.cnc-deco-ring-mini {
  position: absolute; top: 24px; right: 24px;
}
.cnc-deco-ring-mini svg { transform: rotate(-90deg); }
.cnc-deco-rb { fill: none; stroke: rgba(201,168,76,0.12); stroke-width: 3; }
.cnc-deco-rf {
  fill: none; stroke: var(--deco-gold); stroke-width: 3; stroke-linecap: round;
  stroke-dasharray: 138; stroke-dashoffset: 138;
  transition: stroke-dashoffset 1.6s ease;
}
.cnc-deco-prop-sublabel {
  font-size: 9px; letter-spacing: 3px; text-transform: uppercase;
  color: rgba(44,35,24,0.35); font-weight: 300;
}
.cnc-deco-prop-bar {
  height: 1px; background: rgba(201,168,76,0.15);
  margin: 16px 0; position: relative; overflow: hidden;
}
.cnc-deco-prop-bar-fill {
  position: absolute; left: 0; top: 0; height: 100%;
  background: linear-gradient(90deg, var(--deco-gold), var(--deco-gold-light));
  transform: scaleX(0); transform-origin: left;
  animation: cnc-deco-barFill 1.5s ease forwards;
}
.cnc-deco-prop-card:nth-child(1) .cnc-deco-prop-bar-fill { animation-delay: 0.8s; width: 85%; }
.cnc-deco-prop-card:nth-child(2) .cnc-deco-prop-bar-fill { animation-delay: 1.0s; width: 62%; }
.cnc-deco-prop-card:nth-child(3) .cnc-deco-prop-bar-fill { animation-delay: 1.2s; width: 91%; }
@keyframes cnc-deco-barFill { to { transform: scaleX(1); } }
.cnc-deco-tag {
  display: inline-block;
  font-size: 8px; letter-spacing: 3px; text-transform: uppercase;
  color: var(--deco-gold); border: 1px solid var(--deco-gold);
  padding: 2px 8px; margin-top: 12px; font-weight: 300;
}
@media (prefers-reduced-motion: reduce) {
  .cnc-deco-stat, .cnc-deco-prop-card,
  .cnc-deco-prop-bar-fill, .cnc-deco-rf { animation: none; transition: none; }
  .cnc-deco-stat, .cnc-deco-prop-card { opacity: 1; transform: none; }
}
JS
(function () {
  function ease(t) { return t < 0.5 ? 4*t*t*t : 1 - Math.pow(-2*t + 2, 3) / 2; }
  var root = document.querySelector('.cnc-deco');
  if (!root) return;
  root.querySelectorAll('.cnc-num[data-target]').forEach(function (el) {
    var target = parseFloat(el.dataset.target);
    var decimals = parseInt(el.dataset.decimals || 0, 10);
    var duration = 1800;
    setTimeout(function () {
      var start = performance.now();
      function tick(now) {
        var t = Math.min((now - start) / duration, 1);
        var val = ease(t) * target;
        el.textContent = decimals > 0
          ? val.toFixed(decimals)
          : Math.round(val).toLocaleString();
        if (t < 1) requestAnimationFrame(tick);
      }
      requestAnimationFrame(tick);
    }, 400);
  });
  root.querySelectorAll('.cnc-deco-rf[data-pct]').forEach(function (rf) {
    var pct = parseFloat(rf.dataset.pct) / 100;
    var circumference = 2 * Math.PI * 18;
    setTimeout(function () {
      rf.style.strokeDashoffset = circumference * (1 - pct);
    }, 800);
  });
})();