JSFiddle - React, Tailwind, and code Playground

by SvennMats

HTML

<section class="transition-section">
  <div class="transition-grid">
    
    <div class="feature-card">
      <div class="feature-trend positive">
        <svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
          <ellipse cx="12" cy="5" rx="8" ry="3"></ellipse>
          <path d="M4 5v4c0 1.7 3.6 3 8 3s8-1.3 8-3V5"></path>
          <path d="M4 9v4c0 1.7 3.6 3 8 3s8-1.3 8-3V9"></path>
          <path d="M4 13v4c0 1.7 3.6 3 8 3s8-1.3 8-3v-4"></path>
        </svg>
        Ingen dobbel fakturering
      </div>
      <h3 class="feature-title">Fri bruk ut oppsigelsestiden</h3>
      <p class="feature-text">Det skal lønne seg å bytte til Svenn. Du slipper å betale dobbelt mens du venter på at din gamle avtale utløper.</p>
    </div>

    <div class="feature-card">
      <div class="feature-trend positive">
        <svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
          <path d="M14.7 6.3a1 1 0 0 0 0 1.4l1.6 1.6a1 1 0 0 0 1.4 0l3.77-3.77a6 6 0 0 1-7.94 7.94l-6.91 6.91a2.12 2.12 0 0 1-3-3l6.91-6.91a6 6 0 0 1 7.94-7.94l-3.76 3.76z"></path>
        </svg>
        Vi gjør jobben for deg
      </div>
      <h3 class="feature-title">Gratis bistand med oppsett</h3>
      <p class="feature-text">Vi hjelper deg i gang! Vi laster opp prislistene dine og skreddersyr verktøyet nøyaktig etter dine preferanser.</p>
    </div>

    <div class="feature-card">
      <div class="feature-trend positive">
        <svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
          <path d="M3 18v-6a9 9 0 0 1 18 0v6"></path>
          <path d="M21 19a2 2 0 0 1-2 2h-1a2 2 0 0 1-2-2v-3a2 2 0 0 1 2-2h3zM3 19a2 2 0 0 0 2 2h1a2 2 0 0 0 2-2v-3a2 2 0 0 0-2-2H3z"></path>
       ...

CSS

/* --- Sikrer responsivitet --- */
*, *::before, *::after {
  box-sizing: border-box;
}

/* Brand Variabler */
:root {
  --svenn-orange: #F96529;
  --svenn-dark: #241D2D;
  --svenn-res-bg: #EDF3E3;
  --svenn-bg: #F8F9FA;
}

.transition-section {
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
  background-color: #ffffff;
  padding: 30px 20px; /* Endret fra 60px for mer kompakt uttrykk */
  width: 100%;
}

/* Grid for kortene */
.transition-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 300px), 1fr));
  gap: 24px;
  max-width: 1100px;
  margin: 0 auto;
}

/* Designet på selve kortet */
.feature-card {
  background: #E8EEFF; /* Ny lyseblå bakgrunnsfarge */
  border: none; /* Fjernet grå kantlinje da den ikke trengs mot blå bakgrunn */
  border-radius: 16px;
  padding: 32px 28px;
  display: flex;
  flex-direction: column;
  /* Justert skyggen litt for å passe bedre til den blå fargen */
  box-shadow: 0 4px 6px -1px rgba(36, 29, 45, 0.03), 0 2px 4px -1px rgba(36, 29, 45, 0.02);
  transition: transform 0.3s ease, box-shadow 0.3s ease;
  
  /* Start-tilstand for animasjon */
  opacity: 0;
  transform: translateY(30px);
}

.feature-card:hover {
  transform: translateY(-4px);
  box-shadow: 0 12px 20px -3px rgba(36, 29, 45, 0.08), 0 4px 6px -2px rgba(36, 29, 45, 0.04);
}

/* --- STYLING FOR PILLENE --- */
.feature-trend {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 8px 16px;
  border-radius: 20px;
  font-size: 0.9rem;
  font-weight: 600;
  width: fit-content;
  margin-bottom: 24px;
}

/* Siden kortet nå er blått, bruker vi en mørkere pille for kontrast, 
   eller vi kan bruke hvit pille. La oss prøve hvit pille først for friskhet. */
.feature-trend.positive {
  background-color: #ffffff; /* Hvit pille popper bra på blå bakgrunn */
  color: var(--svenn-dark); 
  box-shadow: 0 2px 4px rgba(0,0,0,0.05); /* Liten...

JavaScript

document.addEventListener("DOMContentLoaded", () => {
  const observer = new IntersectionObserver((entries, observer) => {
    entries.forEach(entry => {
      if (entry.isIntersecting) {
        entry.target.classList.add('is-visible');
        observer.unobserve(entry.target);
      }
    });
  }, { 
    threshold: 0.1, 
    rootMargin: "0px 0px -50px 0px" 
  });

  document.querySelectorAll('.feature-card').forEach(card => {
    observer.observe(card);
  });
});