/* ============================================================
   ALMA ERP — Brand Edition
   Same puffy "clay" 3D-pressed UI mechanic as before, retextured
   into the ALMA ERP logo palette: royal blue + deep navy surfaces,
   teal-green "XP" accents, dog-tag badges and HUD-style panels
   instead of the old military-green/camo skin.
   ============================================================ */

/* ---------- 1. Design tokens ---------------------------------------*/
:root {
  --clay-bg: #EEF3FB;          /* page canvas — icy blue-white   */
  --clay-surface: #FFFFFF;     /* default card fill              */
  --clay-surface-pink: #E3ECFC;  /* pale sky blue */
  --clay-surface-mint: #DCF3EA;  /* pale teal-green */
  --clay-surface-sky: #E4E9FA;   /* pale indigo-blue */
  --clay-surface-peach: #FDEEDD; /* soft warm peach (contrast accent) */
  --clay-surface-lavender: #ECE6FB; /* soft purple */
  --clay-surface-yellow: #FDF4D8;   /* soft warm yellow */

  --clay-shadow-dark: rgba(11, 30, 91, 0.35);
  --clay-shadow-light: rgba(255, 255, 255, 0.85);

  --color-primary: #1465D8;
  --color-primary-dark: #0B1E5B;
  --color-primary-light: #4F9BEE;
  --color-text: #10192E;
  --color-text-muted: #57607A;

  --color-accent: #10B981;     /* teal-green — XP, stars, ribbons */
  --color-accent-dark: #0C8F68;
}

html { scroll-behavior: smooth; width: 100%; }

body {
  background: var(--clay-bg);
  color: var(--color-text);
  font-family: "Plus Jakarta Sans", "Poppins", sans-serif;
  /* `overflow-x: hidden` belongs here, on <body> — NOT also (or instead)
     on <html>. Setting it on the root element gets special "propagate to
     the viewport" handling that, in testing, silently broke every
     `position: sticky` element on the site — #site-header just scrolled
     away instead of sticking, because <html> having any non-`visible`
     overflow-x turns <body> into an independent scroll container that
     sticky's containing-block math doesn't resolve the same as the true
     viewport. Keeping it on <body> only still fully prevents horizontal
     overflow, without that side effect. */
  overflow-x: hidden;
  width: 100%;
  /* Magic wand cursor — hotspot (24,13) sits on the star tip so the
     "active" point of the pointer is where the sparkle bursts. */
  cursor: url("../images/cursor/wand-cursor.svg") 24 13, auto;
}

/* Links/buttons get `cursor: pointer` from Tailwind's preflight reset,
   which — since Tailwind CDN injects/updates its <style> tag async and
   can land after this sheet — otherwise wins on equal specificity.
   The extra `body` ancestor bumps specificity so this reliably wins
   regardless of injection order, keeping the wand over every
   clickable element too. */
body a, body button, body [role="button"], body label, body select {
  cursor: url("../images/cursor/wand-cursor.svg") 24 13, pointer;
}

/* Text-entry fields keep the native I-beam — a wand cursor there would
   hide where typed text actually lands. */
input, textarea {
  cursor: text;
}

h1, h2, h3, h4, .font-heading {
  font-family: "Rajdhani", "Plus Jakarta Sans", sans-serif;
  letter-spacing: 0.01em;
}

/* ---------- 2. Clay surface utilities -------------------------------*/

/* Default puffy card */
.clay {
  background: var(--clay-surface);
  border-radius: 1.75rem;
  border: 1px solid rgba(255, 255, 255, 0.7);
  box-shadow: -10px -10px 22px var(--clay-shadow-light),
    12px 14px 26px var(--clay-shadow-dark);
}

/* Smaller puffy surface — chips / icon tiles / inputs */
.clay-sm {
  background: var(--clay-surface);
  border-radius: 1.1rem;
  border: 1px solid rgba(255, 255, 255, 0.7);
  box-shadow: -6px -6px 14px var(--clay-shadow-light),
    8px 9px 16px var(--clay-shadow-dark);
}

/* Recessed clay — search pill, tab track, input fields */
.clay-inset {
  background: #E6EDFA;
  border-radius: 1.1rem;
  border: 1px solid rgba(255, 255, 255, 0.6);
  box-shadow: inset 4px 4px 10px rgba(20, 101, 216, 0.22),
    inset -4px -4px 10px rgba(255, 255, 255, 0.8);
}

/* Circular clay button — icon buttons / avatars / nav arrows */
.clay-circle {
  background: var(--clay-surface);
  border-radius: 50%;
  border: 1px solid rgba(255, 255, 255, 0.7);
  box-shadow: -6px -6px 14px var(--clay-shadow-light),
    8px 9px 16px var(--clay-shadow-dark);
}

/* Color variants so cards can use the camo-tinted surface palette */
.clay-pink { background: var(--clay-surface-pink); }
.clay-mint { background: var(--clay-surface-mint); }
.clay-sky { background: var(--clay-surface-sky); }
.clay-peach { background: var(--clay-surface-peach); }
.clay-lavender { background: var(--clay-surface-lavender); }
.clay-yellow { background: var(--clay-surface-yellow); }

/* Hover squish/lift used across cards */
.clay-hover { transition: transform 0.25s ease, box-shadow 0.25s ease; }
.clay-hover:hover {
  transform: translateY(-6px);
  box-shadow: -12px -12px 26px var(--clay-shadow-light),
    16px 18px 32px var(--clay-shadow-dark);
}

/* ---------- 3. Buttons ------------------------------------------------*/

.btn-primary {
  background: linear-gradient(160deg, var(--color-primary-light), var(--color-primary));
  color: #fff;
  border-radius: 1.1rem;
  border: 1px solid rgba(255, 255, 255, 0.4);
  box-shadow: 0 8px 0 -1px var(--color-primary-dark),
    0 14px 22px rgba(11, 30, 91, 0.4);
  transition: transform 0.18s ease, box-shadow 0.18s ease;
}
.btn-primary:hover { transform: translateY(-3px); }
.btn-primary:active {
  transform: translateY(4px);
  box-shadow: 0 2px 0 -1px var(--color-primary-dark), 0 4px 10px rgba(11, 30, 91, 0.35);
}

.btn-ghost {
  background: var(--clay-surface);
  color: var(--color-text);
  border-radius: 1.1rem;
  border: 1px solid rgba(255, 255, 255, 0.7);
  box-shadow: -6px -6px 14px var(--clay-shadow-light), 8px 9px 16px var(--clay-shadow-dark);
  transition: transform 0.18s ease, box-shadow 0.18s ease;
}
.btn-ghost:hover { transform: translateY(-3px); }
.btn-ghost:active {
  transform: translateY(2px);
  box-shadow: inset 4px 4px 10px rgba(20, 101, 216, 0.2), inset -4px -4px 10px rgba(255, 255, 255, 0.8);
}

/* ---------- 4. Section helpers ---------------------------------------*/

.section-eyebrow { letter-spacing: 0.12em; }

/* ---------- 4b. Transparent-over-video navbar (homepage hero only) ---
   main.js toggles #site-header between this "is-on-dark" state (top of
   the video hero: transparent bg, white text) and its default classes
   (solid bg-sand/90 + backdrop-blur, defined inline in navbar.html) once
   the user scrolls past the hero. The ID selector here is deliberate —
   it needs to outrank the plain-class `.hover:text-primary` utility
   Tailwind puts on each nav link. */
#site-header.is-on-dark {
  background-color: transparent !important;
  backdrop-filter: none;
  box-shadow: none;
}
#site-header.is-on-dark .nav-links,
#site-header.is-on-dark .nav-logo-text {
  color: #fff;
}
#site-header.is-on-dark .nav-links a:hover,
#site-header.is-on-dark .nav-links button:hover {
  color: #fff;
  opacity: 0.75;
}
/* The Solutions dropdown panel always sits on its own light bg-sand
   card, even while the header itself is transparent-with-white-text
   over the video hero. Without this, its links inherit the white
   .nav-links color straight through and go unreadable against that
   light card (white-on-white). Re-pin them to the normal dark/muted
   ink color and drop the hover rule's forced white too. */
#site-header.is-on-dark .nav-links .clay a {
  color: var(--color-text-muted);
}
#site-header.is-on-dark .nav-links .clay a:hover {
  color: var(--color-primary);
  opacity: 1;
}

/* Pulls the video hero up under the sticky header + announcement bar
   (measured at ~112px: 36px bar + 76px header, stable across viewport
   widths since neither wraps to a second line at any supported size)
   so the transparent header floats over the video instead of the
   sticky header pushing it down the page. A couple of px of headroom
   over the measured value is harmless — it just shows a sliver more
   video at the very top edge — so this rounds up rather than trims
   tight. See the JS comment in main.js for why this is CSS, not JS. */
.hero-video {
  margin-top: -116px;
  padding-top: 116px;
}

.text-gradient {
  background: linear-gradient(120deg, var(--color-primary), var(--color-accent));
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
}

.tab-pill {
  border-radius: 1rem;
  color: var(--color-text-muted);
  transition: all 0.2s ease;
}
.tab-pill.is-active {
  color: #fff;
  font-weight: 600;
  background: linear-gradient(160deg, var(--color-primary-light), var(--color-primary));
  box-shadow: 0 6px 14px rgba(11, 30, 91, 0.4);
}

/* "Most popular" badge ribbon used on pricing + programs */
.clay-badge {
  background: linear-gradient(160deg, #4DD9A8, var(--color-accent-dark));
  color: #fff;
  border-radius: 999px;
  box-shadow: 0 6px 14px rgba(12, 143, 104, 0.45);
}
/* One continuous animation on the badge itself (not the text inside):
   rubber-band stretch at rest on the right, then slides left, then
   slides back to the right, on a loop. Sits on an inner span so the
   outer positioning wrapper's centering transform stays untouched. */
@keyframes badge-rubber-slide {
  0%   { transform: translateX(38px) scale3d(1, 1, 1); }
  8%   { transform: translateX(38px) scale3d(1.25, 0.75, 1); }
  16%  { transform: translateX(38px) scale3d(0.75, 1.25, 1); }
  24%  { transform: translateX(38px) scale3d(1.15, 0.85, 1); }
  32%  { transform: translateX(38px) scale3d(0.95, 1.05, 1); }
  40%  { transform: translateX(38px) scale3d(1, 1, 1); }
  65%  { transform: translateX(-38px) scale3d(1, 1, 1); }
  100% { transform: translateX(38px) scale3d(1, 1, 1); }
}
.badge-rubber-slide {
  animation: badge-rubber-slide 4s ease-in-out infinite;
}

/* ---------- 5. Toggle switch (clay) — used in Pricing section --------*/

.clay-toggle {
  width: 56px;
  height: 30px;
  border-radius: 999px;
  background: var(--clay-surface);
  border: 1px solid rgba(255, 255, 255, 0.7);
  box-shadow: inset 3px 3px 8px rgba(20, 101, 216, 0.25), inset -3px -3px 8px rgba(255, 255, 255, 0.8);
  position: relative;
  cursor: pointer;
  flex-shrink: 0;
  transition: background 0.25s ease;
}
.clay-toggle .clay-toggle-dot {
  position: absolute;
  top: 3px;
  left: 3px;
  width: 22px;
  height: 22px;
  border-radius: 50%;
  background: linear-gradient(160deg, var(--color-primary-light), var(--color-primary));
  box-shadow: 0 3px 6px rgba(11, 30, 91, 0.5);
  transition: transform 0.25s ease;
}
.clay-toggle.is-on .clay-toggle-dot { transform: translateX(26px); }

/* ---------- 6. FAQ accordion ------------------------------------------*/

.faq-item { overflow: hidden; }
.faq-answer {
  max-height: 0;
  overflow: hidden;
  transition: max-height 0.3s ease;
}
.faq-item.is-open .faq-answer { max-height: 240px; }
.faq-item.is-open .faq-chevron { transform: rotate(180deg); }
.faq-chevron { transition: transform 0.25s ease; }

/* ---------- 7. Animations ---------------------------------------------*/

@keyframes float-y { 0%, 100% { transform: translateY(0); } 50% { transform: translateY(-14px); } }
.animate-float { animation: float-y 5s ease-in-out infinite; }
.animate-float-slow { animation: float-y 7s ease-in-out infinite; }
.animate-float-delay { animation: float-y 6s ease-in-out infinite; animation-delay: 1.2s; }

@keyframes pulse-ring {
  0% { box-shadow: 0 0 0 0 rgba(20, 101, 216, 0.35); }
  100% { box-shadow: 0 0 0 22px rgba(20, 101, 216, 0); }
}
.animate-pulse-ring { animation: pulse-ring 2.4s ease-out infinite; }

@keyframes spin-slow { to { transform: rotate(360deg); } }
.animate-spin-slow { animation: spin-slow 16s linear infinite; }

@keyframes fade-up { from { opacity: 0; transform: translateY(24px); } to { opacity: 1; transform: translateY(0); } }
.fade-up { animation: fade-up 0.7s ease forwards; }

/* ---------- 8. Owl Carousel overrides (re-skin to camo) --------------*/

/* Safety net: Owl Carousel's JS measures the container to size its
   (intentionally very wide, all-slides-in-a-row) .owl-stage. On first
   paint — especially with the Tailwind CDN JIT compiling classes async
   — that measurement can race ahead of layout settling, so the stage
   is sized off a stale/too-wide number and leaks past its wrapper,
   pushing the whole page into horizontal overflow on mobile. Container
   + wrapper are hard-capped to their parent's width regardless of
   whatever inline width Owl's JS sets on .owl-stage. */
.owl-carousel,
.owl-carousel .owl-stage-outer {
  max-width: 100%;
  overflow: hidden;
}

.owl-carousel .owl-stage-outer { padding: 0.5rem 0 1.5rem; }

/* .clay cards carry a soft two-tone shadow that bleeds ~25-30px past
   their own edges. .owl-stage-outer's overflow:hidden (needed to hide
   off-stage slides) clips that fade with no horizontal buffer, leaving
   a hard-edged "ghost rectangle" seam next to the card instead of a
   smooth fade. The buffer has to live on .owl-item, NOT
   .owl-stage-outer — Owl's JS sizes/positions items off that
   container's own box, so padding added there desyncs item width from
   the clipping viewport (confirmed: shifted the card ~28px off from
   its own overflow boundary). Padding on the item is invisible to
   that math since Owl only ever sets the item's fixed width/margin.
   Scoped to the single-card (items:1) carousels only — clients/
   integrations show many small items per row, where the same 1.5rem
   eats a third of each slide's width and forces their labels to
   truncate. */
.testimonial-carousel .owl-item,
.platform-carousel .owl-item {
  padding: 0 1.5rem;
}

/* Slides hold variable amounts of text (testimonials especially), so
   each .clay card naturally settles at its own height. Owl's items sit
   in a floated row (not flex — forcing display:flex here fights Owl's
   own inline width/transform math on .owl-stage and visibly shrinks
   the row), which is fine once a slide is settled, but while
   dragging/swiping, the current and next card are visible side by
   side and the shorter one's card stops early, showing a jagged,
   mismatched edge next to the taller one. A shared min-height (tall
   enough for the longest testimonial) keeps every card the same size
   during the drag, not just at rest; items-center on the card's own
   grid keeps shorter content vertically centred inside the extra
   space instead of looking stranded at the top. */
.testimonial-carousel .clay {
  min-height: 320px;
}
@media (max-width: 639px) {
  .testimonial-carousel .clay {
    min-height: 640px;
  }
}

.owl-theme .owl-nav [class*="owl-"] {
  width: 2.75rem;
  height: 2.75rem;
  margin: 0 6px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  background: var(--clay-surface) !important;
  color: var(--color-primary) !important;
  border: 1px solid rgba(255, 255, 255, 0.7);
  border-radius: 50% !important;
  box-shadow: -6px -6px 14px var(--clay-shadow-light), 8px 9px 16px var(--clay-shadow-dark);
  transition: transform 0.2s ease;
}
.owl-theme .owl-nav [class*="owl-"]:hover {
  background: var(--color-primary) !important;
  color: #fff !important;
  transform: translateY(-2px);
}

.owl-theme .owl-dots .owl-dot span {
  width: 9px;
  height: 9px;
  margin: 5px 4px;
  background: rgba(20, 101, 216, 0.3);
}
.owl-theme .owl-dots .owl-dot.active span {
  background: var(--color-primary);
  width: 22px;
  border-radius: 6px;
}

.client-logo-slide { display: flex; align-items: center; justify-content: center; }

/* ---------- 9. Cartoon game-banner background + HUD chrome -------------*/

/* Playful "confetti" banner — solid gradient + uniform cartoon dots/stars.
   Deliberately NOT a camouflage print: even-sized polka dots read as a
   fun game-level banner instead of fabric camo blotches. */
.camo-bg {
  position: relative;
  background-color: var(--color-primary);
  /* Order matters: CSS paints the first background-image on top. A dark
     center vignette sits over the confetti dots so headline/body text
     always has a clean, readable backdrop; the dots stay visible toward
     the edges for the playful game-banner feel. */
  background-image:
    radial-gradient(ellipse 65% 85% at center, rgba(9, 15, 31, 0.55), rgba(9, 15, 31, 0.18) 55%, transparent 75%),
    radial-gradient(circle, rgba(255, 255, 255, 0.55) 0 6px, transparent 7px),
    radial-gradient(circle, rgba(16, 185, 129, 0.6) 0 5px, transparent 6px),
    radial-gradient(circle, rgba(255, 255, 255, 0.35) 0 4px, transparent 5px),
    linear-gradient(135deg, var(--color-primary-light), var(--color-primary) 55%, var(--color-primary-dark));
  background-size: 100% 100%, 70px 70px, 90px 90px, 50px 50px, 100% 100%;
  background-position: 0 0, 0 0, 35px 45px, 18px 30px, 0 0;
  background-repeat: no-repeat, repeat, repeat, repeat, no-repeat;
}

/* Dashed stencil divider used between badges / steps */
.camo-dash {
  border-style: dashed;
  border-color: rgba(20, 101, 216, 0.4);
}

/* HUD corner brackets — appear on hover for "tactical" feel */
.hud-corners { position: relative; }
.hud-corners::before,
.hud-corners::after {
  content: "";
  position: absolute;
  width: 16px;
  height: 16px;
  border: 2px solid var(--color-accent);
  opacity: 0;
  transition: opacity 0.2s ease;
}
.hud-corners::before { top: -4px; left: -4px; border-right: none; border-bottom: none; }
.hud-corners::after { bottom: -4px; right: -4px; border-left: none; border-top: none; }
.hud-corners:hover::before, .hud-corners:hover::after { opacity: 1; }

/* ---------- 10. Unit badges — replaces fake client/partner logos ------*/

.badge-unit {
  display: flex;
  align-items: center;
  justify-content: center;
  flex-direction: column;
  gap: 2px;
  width: 100%;
  height: 100%;
  color: var(--color-primary-dark);
}
.badge-unit-shield {
  width: 2.1rem;
  height: 2.3rem;
  display: grid;
  place-items: center;
  background: linear-gradient(160deg, var(--color-primary-light), var(--color-primary));
  clip-path: polygon(50% 0%, 100% 18%, 100% 65%, 50% 100%, 0% 65%, 0% 18%);
  color: #fff;
  font-weight: 800;
  font-size: 0.8rem;
  flex-shrink: 0;
}
.badge-unit-label {
  font-size: 0.56rem;
  font-weight: 700;
  letter-spacing: 0;
  text-transform: uppercase;
  color: var(--color-text-muted);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  max-width: 100%;
}

/* ---------- 11. Achievement badges — replaces certification logos -----*/

.badge-achievement {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.4rem;
  overflow: hidden;
}
.badge-achievement .badge-achievement-icon {
  width: 3rem;
  height: 3rem;
  display: grid;
  place-items: center;
  border-radius: 999px;
  background: linear-gradient(160deg, var(--color-accent), var(--color-accent-dark));
  color: #fff;
  font-size: 1.2rem;
  box-shadow: 0 6px 14px rgba(12, 143, 104, 0.4);
}
.badge-achievement .badge-achievement-label {
  font-size: 0.68rem;
  font-weight: 700;
  text-align: center;
  color: var(--color-text-muted);
}
.badge-achievement::after {
  content: "";
  position: absolute;
  top: 0; left: -150%;
  width: 60%; height: 100%;
  background: linear-gradient(120deg, transparent, rgba(255,255,255,0.55), transparent);
  animation: badge-shine 3.2s ease-in-out infinite;
}
@keyframes badge-shine { 0% { left: -150%; } 60% { left: 150%; } 100% { left: 150%; } }

/* ---------- 12. XP / progress bars -------------------------------------*/

.xp-bar {
  width: 100%;
  height: 0.6rem;
  border-radius: 999px;
  background: #DCE6F5;
  box-shadow: inset 2px 2px 5px rgba(20, 101, 216, 0.25);
  overflow: hidden;
}
.xp-bar-fill {
  height: 100%;
  width: 0%;
  border-radius: 999px;
  background: linear-gradient(90deg, var(--color-accent), var(--color-primary));
  transition: width 1.2s ease-out;
}

/* ---------- 13. Mission roadmap steps ----------------------------------*/

.rank-step {
  position: relative;
  text-align: center;
}
.rank-step .rank-medallion {
  width: 4rem;
  height: 4rem;
  margin: 0 auto;
  border-radius: 50%;
  display: grid;
  place-items: center;
  font-weight: 800;
  font-size: 1.3rem;
  color: #fff;
  background: linear-gradient(160deg, var(--color-primary-light), var(--color-primary));
  border: 3px solid var(--clay-bg);
  box-shadow: 0 6px 14px rgba(11, 30, 91, 0.4);
  position: relative;
  z-index: 2;
}
.rank-trail {
  position: absolute;
  top: 2rem;
  left: 0;
  right: 0;
  height: 0;
  border-top: 3px dashed var(--color-primary-light);
  z-index: 1;
}

/* ---------- 14. Leaderboard comparison table ---------------------------*/

.leaderboard-table { width: 100%; border-collapse: separate; border-spacing: 0; }
.leaderboard-table th, .leaderboard-table td {
  padding: 0.9rem 1rem;
  text-align: center;
  font-size: 0.875rem;
}
.leaderboard-table th { font-family: "Rajdhani", sans-serif; font-size: 1rem; }
.leaderboard-table td:first-child, .leaderboard-table th:first-child { text-align: left; }
.leaderboard-table tbody tr:nth-child(odd) { background: rgba(255, 255, 255, 0.4); }
.leaderboard-table .col-winner { background: rgba(16, 185, 129, 0.16); font-weight: 700; }
.leaderboard-table th.col-winner {
  background: linear-gradient(160deg, var(--color-accent), var(--color-accent-dark));
  color: #fff;
  border-radius: 1rem 1rem 0 0;
}

/* ---------- 15. Field report / case-study cards -------------------------*/

.field-report-card { overflow: hidden; }
.field-report-photo {
  height: 11rem;
  background-size: cover;
  background-position: center;
  position: relative;
}

/* Rendered Quill post body (marketing/blog/detail.html) — Tailwind's CDN
   build doesn't ship the Typography plugin, so this hand-rolls just enough
   `prose`-style defaults for the tag set sanitize_html() in backend-portal's
   app/academic/service.py actually allows through. */
.blog-content { font-size: 1.0625rem; line-height: 1.75; }
.blog-content > *:first-child { margin-top: 0; }
.blog-content p { margin: 0 0 1.25em; }
.blog-content h1, .blog-content h2, .blog-content h3,
.blog-content h4, .blog-content h5, .blog-content h6 {
  font-weight: 800; line-height: 1.3; margin: 1.75em 0 0.75em;
}
.blog-content h1 { font-size: 1.75rem; }
.blog-content h2 { font-size: 1.5rem; }
.blog-content h3 { font-size: 1.25rem; }
.blog-content h4, .blog-content h5, .blog-content h6 { font-size: 1.0625rem; }
.blog-content ul, .blog-content ol { margin: 0 0 1.25em; padding-left: 1.5em; }
.blog-content ul { list-style: disc; }
.blog-content ol { list-style: decimal; }
.blog-content li { margin: 0.35em 0; }
.blog-content a { color: var(--color-primary); font-weight: 600; text-decoration: underline; text-underline-offset: 2px; }
.blog-content strong { font-weight: 800; }
.blog-content blockquote {
  margin: 1.5em 0; padding: 0.25em 0 0.25em 1.25em;
  border-left: 3px solid var(--color-primary-light);
  color: var(--color-text-muted); font-style: italic;
}
.blog-content img { border-radius: 1.1rem; margin: 1.5em 0; max-width: 100%; height: auto; }
.blog-content pre, .blog-content code {
  background: var(--clay-surface); border-radius: 0.5rem; font-size: 0.9em;
}
.blog-content code { padding: 0.15em 0.4em; }
.blog-content pre { padding: 1em; overflow-x: auto; margin: 0 0 1.25em; }

/* Quill's toolbar renders align/font/size/indent as class names rather than
   inline styles (see backend-portal's sanitize_html allowlist comment) —
   these reproduce that subset of Quill's own CSS so a post author's choices
   still render correctly on the public page, without pulling in the whole
   editor stylesheet just for a handful of utility classes. */
.blog-content .ql-align-center { text-align: center; }
.blog-content .ql-align-right { text-align: right; }
.blog-content .ql-align-justify { text-align: justify; }
.blog-content .ql-font-serif { font-family: Georgia, "Times New Roman", serif; }
.blog-content .ql-font-monospace { font-family: "SFMono-Regular", Consolas, monospace; }
.blog-content .ql-size-small { font-size: 0.75em; }
.blog-content .ql-size-large { font-size: 1.5em; }
.blog-content .ql-size-huge { font-size: 2.5em; }
.blog-content .ql-indent-1 { padding-left: 1.5em; }
.blog-content .ql-indent-2 { padding-left: 3em; }
.blog-content .ql-indent-3 { padding-left: 4.5em; }
.blog-content .ql-indent-4 { padding-left: 6em; }
.blog-content .ql-indent-5 { padding-left: 7.5em; }
.blog-content .ql-indent-6 { padding-left: 9em; }
.blog-content .ql-indent-7 { padding-left: 10.5em; }
.blog-content .ql-indent-8 { padding-left: 12em; }

/* Blog category filter pills (marketing/blog/index.html) */
.blog-filter-pill {
  color: var(--color-text-muted);
  transition: all 0.2s ease;
}
.blog-filter-pill.is-active {
  color: #fff;
  background: linear-gradient(160deg, var(--color-primary-light), var(--color-primary));
  box-shadow: 0 6px 14px rgba(11, 30, 91, 0.4);
}
.field-report-photo::after {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(180deg, rgba(16, 25, 46, 0) 40%, rgba(16, 25, 46, 0.55));
}

/* ---------- 15b. hi5 sidebar tabs ---------------------------------------*/

.hi5-tab {
  text-align: left;
  color: var(--color-text-muted);
  cursor: pointer;
  transition: color 0.2s ease, transform 0.18s ease;
}
.hi5-tab:hover { transform: translateX(2px); }
.hi5-tab.is-active { color: var(--color-primary); }

/* ---------- 16. Video briefing mock -------------------------------------*/

.video-player-mock {
  position: relative;
  /* Was a fixed height: 16rem against a much wider (~976px) container —
     briefing.mp4 is 848x478 (16:9), so object-cover had to scale it up
     to fill that squat box and cropped out roughly half the frame
     top-and-bottom to do it. Sizing the box to the video's own ratio
     means nothing needs to be cropped at any container width. */
  aspect-ratio: 848 / 478;
  background: linear-gradient(135deg, var(--color-primary), var(--color-primary-dark));
  display: grid;
  place-items: center;
  overflow: hidden;
}
.video-play-btn {
  width: 4.5rem;
  height: 4.5rem;
  border-radius: 50%;
  background: rgba(255, 255, 255, 0.95);
  color: var(--color-primary);
  display: grid;
  place-items: center;
  font-size: 1.4rem;
  position: relative;
  z-index: 2;
  /* Was flat (no shadow at all) — every other circular icon on the page
     is a puffy .clay-circle; this one got missed. Same shadow recipe. */
  border: 1px solid rgba(255, 255, 255, 0.7);
  box-shadow: -6px -6px 14px var(--clay-shadow-light), 8px 9px 16px var(--clay-shadow-dark);
}

/* ---------- 17. Phone / tablet device mockups ---------------------------*/

.device-frame {
  background: linear-gradient(160deg, #1D2E63, #10192E);
  border-radius: 1.6rem;
  padding: 0.5rem;
  box-shadow: 0 14px 26px rgba(16, 25, 46, 0.45);
}
.device-frame .device-screen {
  background: var(--clay-surface);
  border-radius: 1.1rem;
  overflow: hidden;
}
.device-notch {
  width: 2.5rem;
  height: 0.35rem;
  border-radius: 999px;
  background: rgba(255, 255, 255, 0.25);
  margin: 0.35rem auto;
}

/* ---------- 18. Misc ----------------------------------------------------*/

.marquee-mask { mask-image: linear-gradient(90deg, transparent, #000 8%, #000 92%, transparent); }

::-webkit-scrollbar { width: 10px; }
::-webkit-scrollbar-track { background: var(--clay-bg); }
::-webkit-scrollbar-thumb { background: var(--color-primary-light); border-radius: 10px; }

/* ---------- 19. Decorative nature / orbit-of-modules accents -----------
   Clouds, spirals, lotus doodles, stars, trees, bushes and grass tufts
   scattered around the mascot & section corners. Everything here reads
   in the existing camo/olive/gold tokens — no new colors introduced. */

.decor {
  position: absolute;
  pointer-events: none;
  user-select: none;
  z-index: 5;
}

@keyframes cloud-drift { 0%, 100% { transform: translateX(0); } 50% { transform: translateX(16px); } }
.decor-cloud { animation: cloud-drift 9s ease-in-out infinite; }
.decor-cloud.decor-cloud-slow { animation-duration: 13s; }

@keyframes twinkle { 0%, 100% { opacity: 0.25; transform: scale(0.85); } 50% { opacity: 1; transform: scale(1.1); } }
.decor-star { animation: twinkle 2.6s ease-in-out infinite; }

/* Dashed "orbit" ring + small clay module badges continuously revolving
   around the mascot, echoing a mini solar-system around the hero visual.
   .orbit-system is the circle's bounding box; .orbit-ring-spin is the
   dashed path itself and continuously rotates. Each .orbit-track spins
   clockwise a full 360° on a loop while its .orbit-item child runs the
   mirrored counter-spin at the identical rate — so every icon+label
   travels the ring while always reading upright. Items share one
   duration but start at staggered NEGATIVE animation-delays (an even
   fraction of the duration apart) so they stay evenly spaced as they
   orbit. Tablet (md) keeps the mascot fully inside the panel with the
   full ring showing. Large screens (lg+) scale the mascot up and pull
   the whole system up by half its own height, so its center sits
   exactly on the panel's top edge — the mascot reads as "popping out"
   of the dark panel into the cream page background above it, and only
   the bottom half of the ring is visible against the panel. */
.orbit-system {
  position: absolute;
  width: 240px;
  height: 240px;
  bottom: 4px;
  right: 4px;
}
.orbit-system-mascot {
  position: absolute;
  inset: 0;
  margin: auto;
  width: 128px;
  height: 128px;
  object-fit: contain;
  filter: drop-shadow(0 8px 14px rgba(16, 25, 46, 0.4));
}
.orbit-ring-spin {
  position: absolute;
  inset: 0;
  margin: auto;
  width: 240px;
  height: 240px;
  border: 2px dashed var(--color-primary-light);
  border-radius: 50%;
  opacity: 0.45;
  animation: spin-slow 24s linear infinite;
}
.orbit-ring-spin.is-inner {
  width: 176px;
  height: 176px;
  opacity: 0.3;
  animation-duration: 18s;
  animation-direction: reverse;
}
@keyframes orbit-revolve {
  from { transform: rotate(0deg); }
  to { transform: rotate(360deg); }
}
@keyframes orbit-counter-revolve {
  from { transform: translate(-50%, -50%) translateY(calc(-1 * var(--orbit-radius, 122px))) rotate(0deg); }
  to { transform: translate(-50%, -50%) translateY(calc(-1 * var(--orbit-radius, 122px))) rotate(-360deg); }
}
.orbit-track {
  position: absolute;
  top: 50%;
  left: 50%;
  width: 0;
  height: 0;
  animation: orbit-revolve 24s linear infinite;
  animation-delay: var(--delay, 0s);
}
/* Orbit item = icon badge + label, orbiting the ring radius while
   counter-spinning to stay upright, each in its own tone drawn from
   the existing primary/accent palette. */
.orbit-item {
  position: absolute;
  top: 0;
  left: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.4rem;
  --orbit-radius: 122px;
  animation: orbit-counter-revolve 24s linear infinite;
  animation-delay: var(--delay, 0s);
}

/* Large screens — mascot scales up and the whole system shifts so its
   center lands on the panel's BOTTOM edge, right corner (half in the
   cream page bg below, half over the dark panel). Tablet/md is
   untouched by this block. */
@media (min-width: 1024px) {
  .orbit-system {
    width: 380px;
    height: 380px;
    top: auto;
    bottom: -190px;
    right: -80px;
  }
  .orbit-system-mascot {
    width: 190px;
    height: 190px;
  }
  .orbit-ring-spin {
    width: 300px;
    height: 300px;
  }
  .orbit-ring-spin.is-inner {
    width: 215px;
    height: 215px;
  }
  .orbit-item {
    --orbit-radius: 150px;
  }
}
.orbit-item-icon {
  width: 3.4rem;
  height: 3.4rem;
  border-radius: 50%;
  display: grid;
  place-items: center;
  font-size: 1.25rem;
  color: #fff;
  border: 1px solid rgba(255, 255, 255, 0.5);
  box-shadow: 0 8px 16px rgba(16, 25, 46, 0.4);
}
.orbit-item-icon.is-primary { background: linear-gradient(160deg, var(--color-primary-light), var(--color-primary)); }
.orbit-item-icon.is-dark { background: linear-gradient(160deg, var(--color-primary), var(--color-primary-dark)); }
.orbit-item-icon.is-accent { background: linear-gradient(160deg, #4DD9A8, var(--color-accent-dark)); }
.orbit-item-icon.is-light { background: linear-gradient(160deg, #9DCBFA, var(--color-primary-light)); }
.orbit-item-label {
  font-size: 0.7rem;
  font-weight: 700;
  color: var(--color-text);
  background: rgba(255, 255, 255, 0.92);
  padding: 0.2rem 0.6rem;
  border-radius: 999px;
  white-space: nowrap;
  box-shadow: 0 2px 6px rgba(16, 25, 46, 0.15);
}

/* Little "Hey!" speech-bubble tooltip, anchored to the top-right corner
   of .orbit-system itself so it travels with the mascot cluster at
   every breakpoint instead of needing its own separate positioning. */
.orbit-bubble {
  position: absolute;
  top: 14%;
  right: 4%;
  background: var(--color-primary);
  color: #fff;
  font-weight: 800;
  font-size: 0.7rem;
  padding: 0.35rem 0.75rem;
  border-radius: 999px 999px 999px 4px;
  box-shadow: 0 8px 16px rgba(16, 25, 46, 0.35);
}

.decor-tree, .decor-bush, .decor-grass { opacity: 0.5; }
.decor-spiral, .decor-lotus { opacity: 0.6; }
.decor-star-icon { opacity: 0.85; }

/* ---------- 20. Magic wand cursor trail --------------------------------
   A little gold sparkle-star spawns wherever the mouse travels, then
   pops and fades — like a wand swept through and left glitter behind.
   Spawned/removed from JS (main.js); purely decorative, never blocks
   clicks (pointer-events: none), and JS gates it off on touch devices
   and prefers-reduced-motion. */
.cursor-sparkle {
  position: fixed;
  top: 0;
  left: 0;
  pointer-events: none;
  z-index: 9999;
  background: radial-gradient(circle at 35% 30%, #E0FFF4, var(--color-accent) 55%, var(--color-accent-dark) 100%);
  clip-path: polygon(50% 0%, 61% 35%, 100% 50%, 61% 65%, 50% 100%, 39% 65%, 0% 50%, 39% 35%);
  will-change: transform, opacity;
  animation: cursor-sparkle-pop 0.75s ease-out forwards;
}
@keyframes cursor-sparkle-pop {
  0% { opacity: 0.95; transform: translate(-50%, -50%) scale(0.3) rotate(0deg); }
  25% { opacity: 1; transform: translate(-50%, -50%) scale(1) rotate(35deg); }
  100% { opacity: 0; transform: translate(-50%, -75%) scale(0.15) rotate(80deg); }
}

/* ---------- 21. Tactical field — ambient signal-node background --------
   Client reference showed continuously-animating dot/line particle
   fields behind full-width panels. Re-skinned here as a "tactical HUD"
   signal network (drifting nodes, faint grid, radar pings) using the
   existing brand tokens, so it reads as an extension of the
   orbit-system/HUD-corners language already on the page rather than a
   bolted-on dark/neon effect. Pure CSS: one <span> per node, positioned
   via inline --x/--y/--delay custom properties the same way
   .orbit-track already does. Applied only to the big single full-width
   panels (hero visual, stats, leaderboard, hi5, app showcase, CTA,
   footer) — not the small repeating card grids, where this many nodes
   would just be visual noise.

   z-index is negative on purpose: most host panels have non-positioned
   in-flow content (plain text/table/etc.), which paints above
   z-index:0 positioned siblings regardless of DOM order. A negative
   z-index is the one value that reliably sits behind that content. The
   host panel must add `isolate` alongside its `relative` so that
   negative z-index stays scoped to this panel instead of escaping
   behind earlier page content. */

.field {
  position: absolute;
  inset: 0;
  overflow: hidden;
  pointer-events: none;
  z-index: -1;
}

/* near-invisible tactical graph-paper grid, slowly panning */
.field-grid {
  position: absolute;
  inset: -42px;
  background-image:
    linear-gradient(rgba(20, 101, 216, 0.08) 1px, transparent 1px),
    linear-gradient(90deg, rgba(20, 101, 216, 0.08) 1px, transparent 1px);
  background-size: 42px 42px;
  animation: field-grid-drift 34s linear infinite;
}
.field.is-on-dark .field-grid {
  background-image:
    linear-gradient(rgba(238, 243, 251, 0.1) 1px, transparent 1px),
    linear-gradient(90deg, rgba(238, 243, 251, 0.1) 1px, transparent 1px);
}
@keyframes field-grid-drift { to { background-position: 42px 42px; } }

/* small drifting signal node — fades in, drifts, fades out, on a loop */
.field-dot {
  position: absolute;
  top: var(--y, 50%);
  left: var(--x, 50%);
  width: var(--size, 6px);
  height: var(--size, 6px);
  border-radius: 50%;
  background: var(--color-primary-light);
  opacity: 0;
  animation: field-dot-drift var(--duration, 10s) ease-in-out infinite;
  animation-delay: var(--delay, 0s);
}
.field-dot.is-accent { background: var(--color-accent); }
.field-dot.is-light { background: #fff; }
@keyframes field-dot-drift {
  0%   { opacity: 0; transform: translate(0, 0) scale(0.6); }
  15%  { opacity: 0.8; }
  50%  { opacity: 0.9; transform: translate(var(--drift-x, 14px), calc(-1 * var(--drift-y, 20px))) scale(1); }
  85%  { opacity: 0.45; }
  100% { opacity: 0; transform: translate(calc(var(--drift-x, 14px) * 2), calc(-2 * var(--drift-y, 20px))) scale(0.6); }
}

/* thin shimmering connector — two nodes "talking", used in the hi5 AI panel */
.field-line {
  position: absolute;
  top: var(--y, 50%);
  left: var(--x, 50%);
  width: var(--length, 120px);
  height: 1px;
  background: linear-gradient(90deg, transparent, rgba(20, 101, 216, 0.45), transparent);
  transform: rotate(var(--angle, 0deg));
  transform-origin: left center;
  opacity: 0;
  animation: field-line-pulse var(--duration, 6s) ease-in-out infinite;
  animation-delay: var(--delay, 0s);
}
@keyframes field-line-pulse {
  0%, 100% { opacity: 0; }
  50% { opacity: 0.7; }
}

/* radar-style expanding rings from a fixed point, echoing .animate-pulse-ring */
.field-ping {
  position: absolute;
  top: var(--y, 50%);
  left: var(--x, 50%);
  width: var(--size, 8px);
  height: var(--size, 8px);
  border-radius: 50%;
  background: var(--color-accent);
  transform: translate(-50%, -50%);
}
.field-ping::before,
.field-ping::after {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: 50%;
  border: 1.5px solid var(--color-accent);
  animation: field-ping-expand var(--duration, 3.5s) ease-out infinite;
}
.field-ping::after { animation-delay: calc(var(--duration, 3.5s) / -2); }
@keyframes field-ping-expand {
  0% { transform: scale(1); opacity: 0.7; }
  100% { transform: scale(9); opacity: 0; }
}

@media (prefers-reduced-motion: reduce) {
  .field-grid, .field-dot, .field-line, .field-ping::before, .field-ping::after {
    animation: none;
  }
  .field-dot { opacity: 0.5; }
  .field-line { opacity: 0.4; }
}

/* ---------- 22. Radar node + wave dots -----------------------------------
   Two small standalone components (no separate section — dropped into
   the right column of an existing 2-col section):
   - .radar-node: a center icon with expanding radar rings around it.
   - .wave-dots: a row of bigger glowing circles that bounce in a
     staggered sequence, so they read as related/synced (a wave) —
     deliberately NOT joined by any connecting line/thread (earlier
     .signal-thread-* approach was reverted; see git history if needed). */

.radar-node {
  position: relative;
  width: 140px;
  height: 140px;
  margin: 0 auto;
}
.radar-icon {
  position: absolute;
  inset: 0;
  margin: auto;
  width: 4.5rem;
  height: 4.5rem;
  border-radius: 50%;
  display: grid;
  place-items: center;
  font-size: 2rem;
  background: linear-gradient(160deg, var(--color-primary-light), var(--color-primary));
  box-shadow: 0 10px 24px rgba(11, 30, 91, 0.35);
}
.radar-wave {
  position: absolute;
  inset: 0;
  margin: auto;
  width: 4.5rem;
  height: 4.5rem;
  border-radius: 50%;
  border: 2px solid var(--color-accent);
  opacity: 0;
  animation: radar-wave-expand 3s ease-out infinite;
}
.radar-wave:nth-child(2) { animation-delay: 1s; }
.radar-wave:nth-child(3) { animation-delay: 2s; }
@keyframes radar-wave-expand {
  0% { transform: scale(1); opacity: 0.6; }
  100% { transform: scale(2.8); opacity: 0; }
}

.wave-dots {
  display: flex;
  align-items: flex-end;
  justify-content: center;
  gap: 1rem;
  height: 70px;
}
.wave-dot {
  width: var(--size, 20px);
  height: var(--size, 20px);
  border-radius: 50%;
  background: var(--color-primary-light);
  box-shadow: 0 0 16px var(--color-primary-light);
  animation: wave-dot-bounce 2.2s ease-in-out infinite;
  animation-delay: var(--delay, 0s);
}
.wave-dot.is-accent {
  background: var(--color-accent);
  box-shadow: 0 0 16px var(--color-accent);
}
@keyframes wave-dot-bounce {
  0%, 100% { transform: translateY(0); opacity: 0.6; }
  50% { transform: translateY(-24px); opacity: 1; }
}

@media (prefers-reduced-motion: reduce) {
  .radar-wave, .wave-dot { animation: none; }
  .radar-wave { opacity: 0.3; }
  .wave-dot { opacity: 0.8; }
}

/* ---------- 23. Orbit sphere — glowing planet + scattered signal dots ---
   Direct match for the client's reference screenshot: a glowing core
   "planet", a thin orbit ring around it, and several loose scattered
   dots (not evenly spaced on the ring — irregular, like the reference)
   that drift gently and continuously. Sits in a dark panel (like
   .video-player-mock/.device-frame already do) so the glow reads the
   same as the reference's black background, in brand colors instead
   of red. Used as the right-column graphic in a text/graphic split
   section — see the "What is ALMA ERP?" section markup. */

.orbit-sphere-panel {
  position: relative;
  background: linear-gradient(160deg, var(--color-primary-dark), #05070f);
  border-radius: 1.75rem;
  overflow: hidden;
  min-height: 320px;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 2rem;
}
.orbit-sphere {
  position: relative;
  width: 100%;
  max-width: 380px;
  aspect-ratio: 1 / 0.8;
}
.orbit-sphere-ring {
  position: absolute;
  top: 50%;
  left: 50%;
  width: 60%;
  aspect-ratio: 1;
  transform: translate(-50%, -50%);
  border: 1.5px solid rgba(20, 101, 216, 0.4);
  border-radius: 50%;
  /* Fixed to the ball on purpose — no spin. It used to rotate
     independently of the core; now it just anchors around it. */
}
.orbit-sphere-core {
  position: absolute;
  top: 50%;
  left: 50%;
  width: 32%;
  aspect-ratio: 1;
  transform: translate(-50%, -50%);
  border-radius: 50%;
  background: radial-gradient(circle at 35% 30%, var(--color-primary-light), var(--color-primary) 55%, var(--color-primary-dark) 100%);
  box-shadow: 0 0 70px 16px rgba(20, 101, 216, 0.5);
  animation: orbit-sphere-breathe 5s ease-in-out infinite;
}
@keyframes orbit-sphere-breathe {
  0%, 100% { transform: translate(-50%, -50%) scale(1); }
  50% { transform: translate(-50%, -50%) scale(1.05); }
}
/* Dots share ONE duration on purpose — only animation-delay differs,
   stepped left-to-right in the markup. That's what makes them read as
   one connected wave (this dot rises just as the last one is settling
   back down) instead of independent random bobbing, like water. */
.orbit-sphere-dot {
  position: absolute;
  top: var(--y, 50%);
  left: var(--x, 50%);
  width: var(--size, 8px);
  height: var(--size, 8px);
  border-radius: 50%;
  background: var(--color-accent);
  box-shadow: 0 0 10px 2px var(--color-accent);
  animation: orbit-sphere-wave 2.4s ease-in-out infinite;
  animation-delay: var(--delay, 0s);
}
.orbit-sphere-dot.is-primary {
  background: var(--color-primary-light);
  box-shadow: 0 0 10px 2px var(--color-primary-light);
}
@keyframes orbit-sphere-wave {
  0%, 100% { transform: translateY(0); }
  50% { transform: translateY(calc(-1 * var(--drift-y, 14px))); }
}

@media (prefers-reduced-motion: reduce) {
  .orbit-sphere-ring, .orbit-sphere-core, .orbit-sphere-dot { animation: none; }
}

/* ---------- 24. Scan target — grid + rings + rotating crosshair ---------
   Direct match for the client's "product card" reference: a faint
   panning grid, two concentric rings, and a spinning 6-spoke crosshair
   with a glowing center — dropped as a background graphic into a
   product-style card (reuses .field-grid from section 21 for the grid
   layer). Host element needs `relative isolate overflow-hidden` — same
   stacking reasoning as .field in section 21. */

.scan-target {
  position: absolute;
  inset: 0;
  overflow: hidden;
  /* Matches the host card's own radius so the grid/rings clip to the
     rounded shape even though the card itself no longer has
     overflow-hidden (that used to clip the "Most Popular" badge, which
     deliberately sits partly above the card via a negative offset). */
  border-radius: inherit;
  pointer-events: none;
  z-index: -1;
}
.scan-rings {
  position: absolute;
  top: 50%;
  right: 10%;
  width: 200px;
  height: 200px;
  transform: translateY(-50%);
}
.scan-ring {
  position: absolute;
  inset: 0;
  margin: auto;
  border: 1.5px solid rgba(20, 101, 216, 0.55);
  border-radius: 50%;
}
.scan-ring.is-inner { width: 60%; height: 60%; }
.scan-crosshair {
  position: absolute;
  inset: 0;
  margin: auto;
  width: 50px;
  height: 50px;
  animation: scan-crosshair-spin 9s linear infinite;
}
.scan-spoke {
  position: absolute;
  inset: 0;
  margin: auto;
  width: 100%;
  height: 1px;
  background: var(--color-accent);
  opacity: 0.8;
  transform: rotate(var(--rot, 0deg));
}
.scan-dot {
  position: absolute;
  inset: 0;
  margin: auto;
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--color-accent);
  box-shadow: 0 0 10px 2px var(--color-accent);
}
@keyframes scan-crosshair-spin { to { transform: rotate(360deg); } }

@media (prefers-reduced-motion: reduce) {
  .scan-crosshair { animation: none; }
}
