:root {
  --bg-dark: #0b0f19;
  --bg-card: #131722;
  --text-main: #FFFFFF;
  --text-muted: #8F9BB3;
  --cyan: #13d8d2;
  --purple: #8a5cff;
  --pink: #ff4fa3;
  --yellow: #ffc928;
  --gold: #FFB300;
  --blue: #2b78ff;
  --green: #10B981;
}

* { margin: 0; padding: 0; box-sizing: border-box; font-family: 'Inter', sans-serif; -webkit-tap-highlight-color: transparent; }
html, body { width: 100%; height: 100%; background-color: var(--bg-dark); color: var(--text-main); overflow-x: hidden;
  /* App UI, not a document: keep panning/pinch but drop double-tap-to-zoom.
     The wait-for-a-second-tap heuristic swallowed quick taps on cards. */
  touch-action: manipulation; }
body { display: flex; flex-direction: column; }

/* Nothing in the UI is meant to be selected.
 *
 * This used to list only a handful of components, which left headings and body
 * copy — the hero title, story text, card labels — selectable. Children drag on
 * everything, and a drag across those smeared a grey selection over the screen
 * that looks exactly like a rendering bug; worse, on the swipe container the
 * drag selected text instead of moving between slides.
 *
 * user-select inherits, so setting it once on the root covers every descendant. */
html,
body {
  -webkit-user-select: none;
  -moz-user-select: none;
  -ms-user-select: none;
  user-select: none;
  -webkit-touch-callout: none;   /* no long-press "copy/share" bubble in the WebView */
}

/* Real text fields must opt back in, or the Writing module's textarea could not
   be typed in, corrected, or selected. */
input,
textarea,
select,
[contenteditable="true"] {
  -webkit-user-select: text;
  -moz-user-select: text;
  -ms-user-select: text;
  user-select: text;
}

/* ============ SYSTEM BAR INSETS ============ */
/* Android 15 (API 35) forces edge-to-edge and no longer lets an app opt out, so
 * the WebView is laid out UNDER the status bar and the gesture bar. On a Pixel 6
 * that put the system clock straight through the "AI English Buddy" wordmark and
 * the wifi/battery icons over the Profile avatar.
 *
 * React Native's own SafeAreaView is an iOS-only no-op, which is why the app
 * looked correct in a browser and wrong on the device. App.js now reads the real
 * insets with react-native-safe-area-context and injects them here.
 *
 * Both default to 0, so the browser and the PWA are unaffected — and the artwork
 * still bleeds to all four edges, which is the part of edge-to-edge we want. */
:root {
  /* env(), not a flat 0. On iOS this is the only thing keeping the header out
     from under the notch — WKWebView reports these correctly and App.js
     deliberately does not inject on iOS, where its measured insets are 0.
     Android WebView always reports 0 here whatever the viewport-fit, so the
     value stays 0 until the measured one is injected over it. A browser and the
     PWA are unaffected: no notch, no inset, artwork still bleeds to all edges. */
  --safe-top: env(safe-area-inset-top, 0px);
  --safe-bottom: env(safe-area-inset-bottom, 0px);
}

/* ============ TOP NAV ============ */
.top-nav {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 10px 16px;
  background: rgba(11, 15, 25, 0.95);
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
  position: fixed;
  top: 0; left: 0; right: 0;
  z-index: 100;
  border-bottom: 1px solid rgba(255,255,255,0.06);
  /* The bar grows by the status bar height and pads its contents down, so the
     blurred backdrop still reaches the top of the screen. */
  height: calc(50px + var(--safe-top));
  padding-top: calc(10px + var(--safe-top));
}
.logo-area {
  display: flex; align-items: center; gap: 6px;
  font-family: 'Outfit', sans-serif; font-size: 1rem; font-weight: 800; color: #fff;
}
.logo-text span { color: var(--pink); }

/* ============ SCREENS ============ */
.screen-container {
  margin-top: calc(50px + var(--safe-top)); /* nav height + status bar */
  width: 100%;
  min-height: calc(100vh - 50px - var(--safe-top));
  padding-bottom: var(--safe-bottom);
  position: relative;
}

.screen {
  display: none;
  width: 100%;
  min-height: calc(100vh - 50px - var(--safe-top));
}
.screen.active { display: flex; }

/* Swiper horizontal layout on mobile */
@media (max-width: 479.98px) {
  .swiper-container {
    display: flex !important;
    flex-direction: row !important;
    overflow-x: auto !important;
    scroll-snap-type: x mandatory !important;
    scroll-behavior: smooth !important;
    width: 100% !important;
    height: calc(100vh - 50px - var(--safe-top)) !important;
    -webkit-overflow-scrolling: touch !important;
    scrollbar-width: none !important;
  }
  .swiper-container::-webkit-scrollbar {
    display: none !important;
  }
  .swiper-container .swiper-slide {
    display: flex !important;
    flex: 0 0 100% !important;
    flex-shrink: 0 !important;
    width: 100% !important;
    height: 100% !important;
    scroll-snap-align: start !important;
    overflow-y: auto !important;
    box-sizing: border-box !important;
  }
  /* Strip heavy shadows on mobile and use lightweight thin borders.

     `filter` is excluded for [data-keep-filter]: this reset exists to kill
     decorative glows, but it also silently killed functional filters —
     the greyed-out state of a completed daily quest and the sepia tint on the
     tense cards both vanished on mobile with no error to explain it. An
     !important declaration beats an inline style, so opting out has to happen
     here rather than at the element. */
  *, *::before, *::after {
    box-shadow: none !important;
    text-shadow: none !important;
  }
  *:not([data-keep-filter]), *::before, *::after {
    filter: none !important;
  }
  .feature-card, .word-card-big, .glass-panel, .story-card, .btn-primary, .primary-cta {
    border: 1px solid rgba(255, 255, 255, 0.2) !important;
  }
}

/* ============ HERO SCREEN ============ */
.hero-screen {
  display: flex;
  flex-direction: row;
  align-items: center;
  justify-content: center;
  padding: 10px 16px;
  gap: 12px;
  flex-wrap: wrap;
  max-width: 100%;
  box-sizing: border-box;
  overflow-x: hidden;
  background:
    radial-gradient(ellipse at 50% 20%, rgba(138, 92, 255, 0.08), transparent 60%),
    var(--bg-dark);
}

.hero-left {
  flex: 0 0 120px;
}
.hero-left img {
  width: 100%;
  height: auto;
  object-fit: contain;
  border-radius: 12px;
  box-shadow: 0 10px 20px rgba(0,0,0,0.3);
}

.hero-right {
  flex: 1;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 6px;
}

.hero-right h1 {
  font-size: 1.15rem;
  font-weight: 900;
  line-height: 1.1;
  font-family: 'Outfit', sans-serif;
  margin: 0;
}
.hero-right h1 .teal { color: var(--cyan); }
.hero-right h1 .pink { color: var(--pink); }
.hero-right h1 .yellow { color: var(--yellow); }

.hero-right .subtitle {
  font-size: 0.7rem;
  color: var(--text-muted);
  margin: 0;
}

.trust-row {
  display: flex; flex-direction: column; gap: 4px;
  margin: 4px 0 0 0;
}
.trust-item { display: flex; align-items: center; gap: 6px; }
.trust-icon {
  width: 18px; height: 18px; border-radius: 4px;
  display: flex; align-items: center; justify-content: center;
  font-size: 9px; background: rgba(255,255,255,0.06);
}
.trust-icon.cyan { color: var(--cyan); }
.trust-icon.purple { color: var(--purple); }
.trust-icon.pink { color: var(--pink); }
.trust-item strong { font-size: 8px; font-weight: 700; color: #fff; }
.trust-item small { display: none; } /* Hide descriptions to save space */

.hero-bottom {
  width: 100%;
  display: flex;
  justify-content: center;
  padding-top: 10px;
}

.primary-cta {
  background: linear-gradient(135deg, #FFB300, #FF8F00);
  color: #000;
  border: none;
  padding: 12px 0;
  border-radius: 50px;
  font-size: 0.9rem;
  font-weight: 800;
  display: flex; align-items: center; justify-content: center; gap: 8px;
  cursor: pointer;
  width: 90%;
  max-width: 280px;
  box-shadow: 0 6px 20px rgba(255, 179, 0, 0.35);
  transition: transform 0.2s, box-shadow 0.2s;
}
.primary-cta:active {
  transform: scale(0.97);
}

/* ============ MENU SCREEN ============ */
.menu-screen {
  flex-direction: column;
  /* the extra bottom pad clears the gesture bar on Android 15 */
  padding: 12px 12px calc(12px + var(--safe-bottom));
  overflow-y: auto;
  -webkit-overflow-scrolling: touch;
  /* Noticeably lighter than --bg-dark, on purpose. The cards are dark carved
     stone: on the near-black page background they melted together on a phone
     screen. A brighter night-indigo behind them makes the plaques and their
     gold frames pop. Plain gradient, no texture — the earlier stone-wall
     backdrop failed precisely because the background resembled the cards. */
  background:
    radial-gradient(ellipse at 50% 0%, rgba(32, 215, 209, 0.08), transparent 55%),
    linear-gradient(180deg, #3a4470 0%, #2b3355 50%, #202744 100%);
}

.menu-header {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 8px 4px 14px;
}
.menu-header .back-btn {
  background: rgba(255,255,255,0.08);
  border: none;
  color: #fff;
  width: 32px; height: 32px;
  border-radius: 10px;
  font-size: 1rem;
  cursor: pointer;
  display: flex; align-items: center; justify-content: center;
}
.menu-header h2 {
  font-family: 'Outfit', sans-serif;
  font-size: 1.1rem;
  font-weight: 800;
  color: #fff;
}

/* ============ FEATURE GRID ============ */
.feature-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 10px;
  width: 100%;
  padding-bottom: 24px;
}

/* ============ FEATURE CARD ============ */
.feature-card {
  width: 100%;
  /* 3:4, the shape the plaque artwork is drawn at. It used to be 1:1, which
     meant object-fit: cover threw away a quarter of every portrait card — and
     threw away a different amount from each one, so the plaques rendered at
     visibly different sizes. */
  aspect-ratio: 1086 / 1551;
  position: relative;
  overflow: hidden;
  border-radius: 16px;
  padding: 10px 8px;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: space-between;
  background:
    linear-gradient(180deg, rgba(255,255,255,0.05), rgba(255,255,255,0.015)),
    #101722;
  border: 1px solid rgba(255,255,255,0.08);
  box-shadow: 0 8px 20px rgba(0,0,0,0.3), inset 0 1px 0 rgba(255,255,255,0.06);
  cursor: pointer;
  transition: transform 0.2s, box-shadow 0.3s;
  -webkit-tap-highlight-color: transparent;
}

.feature-card::before {
  content: "";
  position: absolute; inset: 0;
  background:
    radial-gradient(circle at 50% 10%, var(--soft), transparent 45%),
    radial-gradient(circle at 50% 100%, rgba(255,255,255,0.03), transparent 50%);
  opacity: 0.8;
  pointer-events: none;
}

.feature-card::after {
  content: "";
  position: absolute; inset: 0;
  border-radius: inherit;
  border: 1px solid var(--edge);
  opacity: 0.85;
  pointer-events: none;
}

/* Lift + colour glow on hover, matching the Games Hub cards. Those do it with
   inline JS; here it is CSS. transition covers both enter and leave so it eases
   in and out instead of snapping. Only where a pointer can actually hover. */
.feature-card {
  transition: transform 0.2s cubic-bezier(0.22, 1, 0.36, 1), box-shadow 0.2s ease;
}
@media (hover: hover) {
  .feature-card:hover {
    transform: translateY(-6px) scale(1.03);
    box-shadow: 0 14px 32px rgba(0,0,0,0.5), 0 0 26px var(--glow);
    z-index: 2;
  }
}
.feature-card:active {
  transform: scale(0.95);
  box-shadow: 0 4px 12px rgba(0,0,0,0.4), 0 0 30px var(--glow);
}

/* Premium marker on the artwork cards. The card itself is not dimmed and stays
   fully tappable: the point is to make a child ask a parent for it, not to make
   the app look broken. It anchors to .feature-card, which is already
   position:relative (see the aspect-ratio rule above). */
.card-lock {
  position: absolute;
  top: 8px; right: 8px;
  z-index: 3;
  font-size: 1.05rem;
  line-height: 1;
  padding: 5px 6px;
  border-radius: 999px;
  background: rgba(15,15,25,0.62);
  border: 1px solid rgba(245,158,11,0.55);
  box-shadow: 0 2px 8px rgba(0,0,0,0.35);
  pointer-events: none;
}

.icon-wrap {
  position: relative; z-index: 1;
  width: 36px; height: 36px;
  display: grid; place-items: center;
  color: var(--main);
  filter: drop-shadow(0 0 8px var(--glow));
}
.icon-wrap svg { width: 100%; height: 100%; }
.icon-wrap text { fill: #090d15; stroke: none; font-family: Inter, system-ui, sans-serif; }

.card-copy {
  position: relative; z-index: 1;
  text-align: center;
}
.card-copy h3 {
  margin: 0;
  font-size: 11px;
  line-height: 1.15;
  font-weight: 800;
  letter-spacing: -0.02em;
  color: #fff;
}

.badge {
  position: relative; z-index: 1;
  height: 18px;
  padding: 0 7px;
  display: inline-flex; align-items: center; justify-content: center; gap: 3px;
  border-radius: 999px;
  background: color-mix(in srgb, var(--main) 14%, transparent);
  border: 1px solid color-mix(in srgb, var(--main) 36%, transparent);
  color: var(--main);
  font-size: 8px;
  font-weight: 800;
}
.badge span { font-size: 8px; }

/* Card accent colors */
.feature-card.cyan   { --main: #20d7d1; --edge: rgba(32,215,209,0.6); --glow: rgba(32,215,209,0.2); --soft: rgba(32,215,209,0.08); }
.feature-card.teal   { --main: #19c8bd; --edge: rgba(25,200,189,0.6); --glow: rgba(25,200,189,0.2); --soft: rgba(25,200,189,0.08); }
.feature-card.purple { --main: #8b5cf6; --edge: rgba(139,92,246,0.6); --glow: rgba(139,92,246,0.2); --soft: rgba(139,92,246,0.08); }
.feature-card.pink   { --main: #f0529a; --edge: rgba(240,82,154,0.6); --glow: rgba(240,82,154,0.18); --soft: rgba(240,82,154,0.08); }
.feature-card.yellow { --main: #f6bd30; --edge: rgba(246,189,48,0.6); --glow: rgba(246,189,48,0.18); --soft: rgba(246,189,48,0.07); }
.feature-card.blue   { --main: #3b82f6; --edge: rgba(59,130,246,0.6); --glow: rgba(59,130,246,0.18); --soft: rgba(59,130,246,0.08); }

/* ============ QUEST PANEL (in menu screen) ============ */
.quest-panel {
  background: var(--bg-card);
  border-radius: 16px;
  padding: 14px;
  border: 1px solid rgba(255,255,255,0.05);
  margin-top: 4px;
}
.quest-header {
  display: flex; justify-content: space-between; align-items: center;
  margin-bottom: 12px;
}
.quest-header h3 {
  font-family: 'Outfit', sans-serif; font-size: 0.9rem; font-weight: 700;
  display: flex; align-items: center; gap: 6px; color: #fff;
}
.quest-header p { font-size: 0.75rem; color: var(--text-muted); }
.chest {
  width: 50px; height: 50px; object-fit: contain;
  filter: drop-shadow(0 0 10px rgba(138,92,255,0.6));
  mix-blend-mode: screen;
}
.quest-list { display: flex; flex-direction: column; gap: 6px; }
.quest-item {
  display: flex; align-items: center; gap: 8px;
  background: rgba(255,255,255,0.02);
  padding: 8px; border-radius: 10px;
  border: 1px solid rgba(255,255,255,0.04);
}
.quest-icon {
  width: 28px; height: 28px; border-radius: 7px;
  display: flex; align-items: center; justify-content: center; flex-shrink: 0;
}
.quest-icon svg { width: 16px; height: 16px; }
.quest-icon.cyan   { color: var(--bg-card); background: var(--cyan); }
.quest-icon.purple { color: var(--bg-card); background: var(--purple); }
.quest-icon.pink   { color: var(--bg-card); background: var(--pink); }
.quest-item-content { flex: 1; min-width: 0; }
.quest-item-content strong { font-size: 0.7rem; color: #fff; font-weight: 700; display: block; }
.quest-item-row { display: flex; justify-content: space-between; align-items: center; }
.quest-item-row small { font-size: 0.6rem; color: var(--text-muted); }
.quest-item-row em { font-weight: 800; font-style: normal; font-size: 0.6rem; }
.quest-item-row em.cyan-text   { color: var(--cyan); }
.quest-item-row em.purple-text { color: var(--purple); }
.quest-item-row em.pink-text   { color: var(--pink); }

/* ============ ANIMATIONS ============ */
@keyframes fadeIn {
  from { opacity: 0; transform: translateY(12px); }
  to   { opacity: 1; transform: translateY(0); }
}
.screen.active {
  animation: fadeIn 0.3s ease-out;
}

/* ============ LARGER SCREENS ============ */
@media (min-width: 480px) {
  .feature-grid { grid-template-columns: repeat(4, 1fr); gap: 12px; }
  .icon-wrap { width: 44px; height: 44px; }
  .card-copy h3 { font-size: 13px; }
  .badge { height: 22px; padding: 0 8px; font-size: 9px; }
}

@media (min-width: 768px) {
  .feature-grid { grid-template-columns: repeat(4, 1fr); gap: 16px; }
  .feature-card { border-radius: 20px; padding: 14px 10px; }
  .icon-wrap { width: 56px; height: 56px; }
  .card-copy h3 { font-size: 15px; }
  .badge { height: 26px; padding: 0 10px; font-size: 10px; }
}

/* ============ DESKTOP ============
   Above 768px there used to be no rule at all, so the grid stayed at four
   columns for ever and each card simply stretched with the window. Measured on
   the deployed app: a 1920-wide window showed four cards and half a row, and a
   2560-wide one showed exactly the same four — a bigger monitor bought bigger
   plaques, never more of them, and 26 cards took seven screens of scrolling.

   Columns are sized rather than counted so the layout keeps adapting past any
   breakpoint we happen to think of: cards settle around 210-260px, which is
   roughly their size on a phone, and the column count follows the window. */
@media (min-width: 1024px) {
  .feature-grid {
    grid-template-columns: repeat(auto-fill, minmax(210px, 1fr));
    gap: 18px;
  }
}

@media (max-width: 479.98px) {
  .hero-screen {
    flex-direction: column !important;
    text-align: center !important;
    padding: 0 16px 24px !important;
    gap: 0 !important;
    flex-wrap: nowrap !important;
    align-items: center !important;
    justify-content: space-evenly !important;
  }
  .hero-left {
    flex: none !important;
    max-width: 100% !important;
    width: 100% !important;
    padding: 16px 0 0 !important;
  }
  .hero-left img {
    width: 100% !important;
    height: auto !important;
    border-radius: 20px !important;
    object-fit: cover !important;
  }
  .hero-right {
    display: flex !important;
    flex: 0 0 auto !important;
    flex-direction: column !important;
    align-items: center !important;
    width: 100% !important;
    padding: 16px 0 0 !important;
    gap: 8px !important;
  }
  .hero-right h1 {
    font-size: clamp(1.55rem, 7.7vw, 2.15rem) !important;
    line-height: 1.15 !important;
    text-align: center !important;
  }
  .hero-right .subtitle {
    margin: 4px 0 12px !important;
    font-size: clamp(0.8rem, 3.85vw, 1.05rem) !important;
    text-align: center !important;
  }
  .trust-row {
    flex-direction: row !important;
    gap: 10px !important;
    margin: 0 0 16px !important;
    width: 100% !important;
  }
  .trust-item {
    flex: 1 !important;
    flex-direction: column !important;
    align-items: center !important;
    gap: 6px !important;
    background: rgba(255,255,255,0.05) !important;
    border: 1px solid rgba(255,255,255,0.1) !important;
    border-radius: 16px !important;
    padding: clamp(10px, 3.7vw, 18px) 8px !important;
    text-align: center !important;
  }
  .trust-icon {
    width: clamp(30px, 9.6vw, 42px) !important;
    height: clamp(30px, 9.6vw, 42px) !important;
    border-radius: 10px !important;
    font-size: clamp(1rem, 5.1vw, 1.35rem) !important;
  }
  .trust-item strong {
    font-size: clamp(0.6rem, 3vw, 0.8rem) !important;
  }
  .hero-bottom {
    width: 100% !important;
    padding-top: 8px !important;
  }
  .primary-cta {
    width: 100% !important;
    max-width: 400px !important;
    padding: 16px 0 !important;
    border-radius: 50px !important;
    font-size: clamp(0.95rem, 4.5vw, 1.2rem) !important;
  }
}

@media (max-width: 359.98px) {
  .feature-grid {
    grid-template-columns: repeat(3, 1fr);
    gap: 6px;
  }
  .feature-card {
    padding: 6px 4px;
    border-radius: 12px;
  }
  .icon-wrap {
    width: 28px;
    height: 28px;
  }
  .card-copy h3 {
    font-size: 9px;
  }
  .badge {
    font-size: 8px;
    padding: 0 4px;
    height: 16px;
    line-height: 16px;
  }
}

/* Artwork menu cards.
   The plaque art already contains the icon, the title and the call-to-action,
   so these cards drop the padding and the decorative glow layers and simply
   show the image. `contain` rather than `cover`: the art has a carved border
   that cropping would cut off, exactly as it did on the Games Hub cards. */
.feature-card.art-card {
  padding: 0;
  display: block;
}
.feature-card.art-card::before,
.feature-card.art-card::after {
  display: none;
}
.feature-card.art-card img {
  width: 100%;
  height: 100%;
  /* cover, not contain: eleven of the twelve artworks are square and fill the
     1:1 card either way, but my_stickers is 0.93 and contain would letterbox it
     into a visibly smaller card than its neighbours. */
  object-fit: cover;
  display: block;
  /* Square corners: the artwork carries its own stone wall right out to the
     edge, so rounding here would cut notches in the masonry exactly where the
     cards are supposed to join. */
  border-radius: 0;
}

/* ============ THE CARDS ARE THE WALL ============ */
/* The plaque artwork now has the stone wall and its light painted into it, so
   the wall is not something drawn behind the grid any more — it arrives inside
   each card. All this section has to do is stop anything from breaking the
   join: no gaps, no rounded corners, no borders.

   An earlier version tiled a generated wall.webp under the grid and lit it with
   gradients. That is gone: with the art bleeding to all four edges it was never
   visible, and two walls at different scales would only have fought.

   This block sits after the three breakpoint rules above on purpose — they set
   gap to 12px / 16px / 6px, and at equal specificity source order is what
   closes them. */
.feature-grid {
  gap: 0;
  padding: 0 0 20px;
}

/* The mobile block near the top of this file forces
   `border: 1px solid rgba(255,255,255,0.2) !important` onto every .feature-card.
   Left alone it draws a white lattice straight across the masonry the moment
   the gaps close. Same weapon, higher specificity. */
.feature-grid .feature-card.art-card {
  border: 0 !important;
  border-radius: 0;
}

/* Pressing a plaque lights it. The mobile block kills box-shadow and filter on
   everything, so :active leans on transform, which it leaves alone — and the
   card opts back into filter with data-keep-filter. */
.feature-card.art-card:active {
  transform: scale(0.97);
}
body.calm-mode .feature-card.art-card:active {
  transform: none;
}

/* ============ MENU CARD WAVE-IN ============ */
/* The Games Hub screens fade+rise on entry via `.screen.active`, but the home
   "Choose a Lesson" grid is a separate React app and had no entrance motion.
   This ripples the twelve cards in on a diagonal — delay grows with row+column
   — so the grid fills like a wave rather than appearing all at once. */
@keyframes cardWave {
  from { opacity: 0; transform: translateY(16px) scale(0.96); }
  to   { opacity: 1; transform: translateY(0) scale(1); }
}
.feature-grid .feature-card {
  animation: cardWave 0.5s cubic-bezier(0.22, 1, 0.36, 1) backwards;
}
/* diagonal stagger: delay = (row + col) x 60ms, 3-column grid */
.feature-grid .feature-card:nth-child(1)  { animation-delay: 0ms;   }
.feature-grid .feature-card:nth-child(2)  { animation-delay: 60ms;  }
.feature-grid .feature-card:nth-child(3)  { animation-delay: 120ms; }
.feature-grid .feature-card:nth-child(4)  { animation-delay: 60ms;  }
.feature-grid .feature-card:nth-child(5)  { animation-delay: 120ms; }
.feature-grid .feature-card:nth-child(6)  { animation-delay: 180ms; }
.feature-grid .feature-card:nth-child(7)  { animation-delay: 120ms; }
.feature-grid .feature-card:nth-child(8)  { animation-delay: 180ms; }
.feature-grid .feature-card:nth-child(9)  { animation-delay: 240ms; }
.feature-grid .feature-card:nth-child(10) { animation-delay: 180ms; }
.feature-grid .feature-card:nth-child(11) { animation-delay: 240ms; }
.feature-grid .feature-card:nth-child(12) { animation-delay: 300ms; }
@media (prefers-reduced-motion: reduce) {
  .feature-grid .feature-card { animation: none; }
}
