/*
  Home style: GLASS NOIR.
  Deep dark background, animated soft gradient blobs (pure CSS, no images), frosted glassmorphism
  cards, neon violet/cyan glow. Fixed dark look by design — ignores the site's light/dark toggle,
  same as the other alternate styles.
*/

:root[data-home-style="glass"] {
  --surface: #08090d;
  --surface-alt: #0d0f16;
  --surface-elevated: rgba(18, 19, 30, 0.46);
  --ink: #f4f5fb;
  --ink-soft: #c2c7de;
  --ink-faint: #8991b5;
  --line: rgba(255, 255, 255, 0.14);
  --line-strong: rgba(255, 255, 255, 0.26);
  --accent: #8b6bff;
  --accent-strong: #a98bff;
  --accent-soft: rgba(139, 107, 255, 0.18);
  --accent-2: #2fd8e0;
  --accent-3: #ff5fb8;
  --on-accent: #05060a;

  --radius-sm: 12px;
  --radius-md: 20px;
  --radius-lg: 28px;
  --border-w: 1px;

  --shadow-sm: 0 1px 0 rgba(255, 255, 255, 0.06) inset, 0 8px 24px rgba(0, 0, 0, 0.4);
  --shadow-md: 0 1px 0 rgba(255, 255, 255, 0.07) inset, 0 18px 48px rgba(0, 0, 0, 0.5);
  --shadow-lg: 0 1px 0 rgba(255, 255, 255, 0.08) inset, 0 30px 80px rgba(0, 0, 0, 0.55);

  --font-display: "Sora", "Space Grotesk", system-ui, sans-serif;
  --font-body: "Manrope", "Public Sans", system-ui, sans-serif;
}

:root[data-home-style="glass"] body {
  background: radial-gradient(60% 50% at 15% 0%, rgba(139, 107, 255, 0.19), transparent 60%),
    radial-gradient(55% 45% at 90% 15%, rgba(47, 216, 224, 0.15), transparent 60%), var(--surface);
}

/*
  Unlike Editorial/Playful/Atelier/Studio, Glass Noir has no light-mode variant of its own — every
  color here is a fixed dark-only palette, so the toggle would have literally zero visible effect if
  left on-screen. Every other style keeps it visible on purpose (the "kept visible" reasoning lives
  in home-atelier.css) specifically because clicking it DOES do something there. Hiding it here isn't
  a contradiction of that reasoning, it's the same principle applied to a style where the premise
  (the toggle affects something) no longer holds.
*/
[data-home-style="glass"] .theme-toggle {
  display: none;
}

/* Glass is a fixed dark-background style regardless of the site-wide toggle — pin the logo to the
   light-on-dark variant (see the matching comment in home-atelier.css for why this is necessary). */
[data-home-style="glass"] .brand-logo .logo-light,
[data-home-style="glass"] .footer-logo-mark .logo-light,
[data-home-style="glass"] .mark-swap .logo-light {
  display: none;
}

[data-home-style="glass"] .brand-logo .logo-dark,
[data-home-style="glass"] .footer-logo-mark .logo-dark,
[data-home-style="glass"] .mark-swap .logo-dark {
  display: block;
}

[data-home-style="glass"] .site-header {
  border-bottom-color: var(--line);
}

/*
  Custom scrollbar — see the matching comment in base.css. A violet-to-cyan gradient thumb with a
  soft glow, matching the exact gradient every other gradient element in this style already uses
  (hero-title, price-values, the showcase/pricing accent text). scrollbar-color (Firefox) can't take
  a gradient, so it falls back to a flat --accent there; the richer gradient+glow is Chromium/WebKit
  only, a progressive enhancement rather than something every browser needs to render identically.
  html[data-home-style="glass"]::-webkit-scrollbar-thumb (no combinator) targets <html>'s OWN root
  scrollbar directly — pseudo-elements attach to the element they belong to, not as a descendant of
  it, so a space here would miss the page's main scrollbar entirely and only hit nested scrollable
  elements (like chat.html's .chat-messages) via the second, comma-separated selector below.
*/
html[data-home-style="glass"] {
  scrollbar-color: var(--accent) var(--surface-alt);
}

html[data-home-style="glass"]::-webkit-scrollbar-thumb,
[data-home-style="glass"] ::-webkit-scrollbar-thumb {
  background: linear-gradient(180deg, var(--accent), var(--accent-2));
  box-shadow: 0 0 8px rgba(139, 107, 255, 0.5);
}

html[data-home-style="glass"]::-webkit-scrollbar-thumb:hover,
[data-home-style="glass"] ::-webkit-scrollbar-thumb:hover {
  background: linear-gradient(180deg, var(--accent-strong), var(--accent-2));
  box-shadow: 0 0 14px rgba(139, 107, 255, 0.7);
}

[data-home-style="glass"] .card,
[data-home-style="glass"] .hero-panel,
[data-home-style="glass"] .showcase-card,
[data-home-style="glass"] .launch-item,
[data-home-style="glass"] .work-card,
[data-home-style="glass"] .pricing-card,
[data-home-style="glass"] .faq-item {
  background: var(--surface-elevated);
  backdrop-filter: blur(20px);
  -webkit-backdrop-filter: blur(20px);
  border: var(--border-w) solid var(--line);
}

[data-home-style="glass"] .button-primary {
  background: linear-gradient(120deg, var(--accent), var(--accent-2));
  color: #05060a;
}

[data-home-style="glass"] .button-primary:hover {
  box-shadow: 0 0 0 1px var(--line-strong), 0 12px 32px rgba(139, 107, 255, 0.4);
  transform: translateY(-2px);
}

[data-home-style="glass"] .button-secondary {
  border-color: var(--line-strong);
  background: rgba(255, 255, 255, 0.03);
}

[data-home-style="glass"] .icon-button:hover {
  background: rgba(255, 255, 255, 0.08);
}

/* Decorative floating blobs, fixed to the viewport for the whole homepage scroll ---------- */

[data-home-style="glass"] .deco-marquee {
  display: none;
}

[data-home-style="glass"] .deco-blobs {
  display: block;
  position: fixed;
  inset: 0;
  z-index: -2;
  overflow: hidden;
  pointer-events: none;
}

/*
  IMPORTANT: .deco-blobs (and its darkening scrim below) is only reliably "behind absolutely
  everything on the page" if none of its ancestors establish their own stacking context. It's
  nested inside .hero-grid — if that element ever gets its own z-index again (it used to have
  z-index: 1, removed for exactly this reason), .deco-blobs's z-index: -2 only keeps it behind
  content *within .hero-grid's own stacking context*, not behind later sibling sections like
  .showcase/.process/etc. Since .deco-blobs is position: fixed, it still visually covers the whole
  viewport as you scroll past those later sections — but with an elevated ancestor, it would
  actually paint *above* them instead of behind, silently darkening every bit of text on the page
  by roughly the scrim's opacity. This exact bug shipped once already; don't re-add z-index/
  transform/opacity/filter to .hero or .hero-grid without re-checking this.
*/

/*
  A flat scrim painted over the blobs (::after paints after/above the span children within the
  same fixed layer) — the blobs alone, at full vibrancy, made body text sitting directly over them
  (not inside a card) hard to read, and shifted the perceived color of text inside the translucent
  cards too. This mutes everything uniformly so contrast holds regardless of which blob happens to
  be behind a given section, while still letting the color glow through softly.
*/
[data-home-style="glass"] .deco-blobs::after {
  content: "";
  position: absolute;
  inset: 0;
  background: rgba(6, 7, 12, 0.4);
}

/*
  translate/scale here are the standalone CSS transform properties, not the `transform` shorthand —
  glass-float below animates THESE, deliberately leaving `transform` itself free for
  setupGlassBlobNudge() (site.js) to drive independently via --nudge-x/--nudge-y. Per spec, an
  element's individual translate/rotate/scale properties and its `transform` property compose
  together rather than overwrite each other, so the slow ambient float and the small cursor-nudge
  both apply at once without fighting over one property. The transition below is what turns each
  --nudge-x/y update (set instantly, on every mousemove) into a smooth ease rather than a jittery snap.
*/
[data-home-style="glass"] .deco-blobs span {
  position: absolute;
  border-radius: 50%;
  filter: blur(75px);
  opacity: 0.5;
  translate: 0 0;
  scale: 1;
  animation: glass-float 22s ease-in-out infinite;
  transform: translate(var(--nudge-x, 0px), var(--nudge-y, 0px));
  transition: transform 500ms var(--ease);
}

[data-home-style="glass"] .deco-blobs span:nth-child(1) {
  width: 46vw;
  height: 46vw;
  top: -12vw;
  left: -10vw;
  background: var(--accent);
  animation-delay: 0s;
}

[data-home-style="glass"] .deco-blobs span:nth-child(2) {
  width: 38vw;
  height: 38vw;
  top: 30vh;
  right: -14vw;
  background: var(--accent-2);
  animation-delay: -7s;
}

[data-home-style="glass"] .deco-blobs span:nth-child(3) {
  width: 34vw;
  height: 34vw;
  bottom: -14vw;
  left: 20vw;
  background: var(--accent-3);
  animation-delay: -14s;
}

@keyframes glass-float {
  0%,
  100% {
    translate: 0 0;
    scale: 1;
  }
  50% {
    translate: 4vw -3vw;
    scale: 1.08;
  }
}

/*
  Cursor trail — DOM created/managed entirely by site.js's setupCursorTrail(), scoped here so it
  only ever renders while this style is actually active (the JS side already gates on this too;
  this is belt-and-suspenders, not the only thing preventing it showing elsewhere). Each dot has its
  own transition duration, all increasing — on mousemove every dot is given the *same* target
  transform, so the shorter-duration ones arrive first and the longer ones lag behind, spreading them
  into a comet-tail arrangement purely from CSS transitions, no animation loop needed. The lead dot's
  transition is as close to instant as still looks smooth, so it reads as glued to the cursor.

  z-index is deliberately BELOW .site-header's (40, see components.css), not above it — site.js also
  hides the trail outright while the pointer is over the header, but this is the belt-and-suspenders
  layer: even if that JS check ever missed a frame, the header's own background still paints over the
  dots instead of the trail sitting on top of the logo/nav.

  IMPORTANT — the dots themselves are plain white with normal blending, NOT mix-blend-mode:
  difference each. Putting difference on every dot individually was the first attempt, and it was
  wrong: with N overlapping siblings each independently differencing against whatever's already
  painted, overlapping regions get inverted twice (or more), and double-inverting white against a
  color returns the ORIGINAL color (difference(difference(C,255),255) = C) — so the dots mostly
  inverted *each other* back toward flat color wherever they overlapped, barely touching the real
  page behind them (confirmed by an actual user report of exactly this). The fix is the classic
  "gooey"/metaball technique: let the dots composite normally into one shape first, then apply
  exactly one difference blend to that merged result.

  That merge and that blend deliberately live on TWO DIFFERENT elements, not one — `.cursor-trail-
  blob` carries only `filter: url(#cursor-goo)` (defined by site.js as an injected, hidden
  <svg><filter>: a Gaussian blur softens/overlaps the dots' edges, then a feColorMatrix boosts the
  alpha channel's contrast so the blurred overlaps snap back into one continuous, organically-
  connected shape instead of N separate circles), while `mix-blend-mode: difference` sits on its
  parent, `.cursor-trail`. Putting both on the same element was the second attempt, and it was also
  wrong: `filter` renders its element into its own isolated intermediate buffer before compositing,
  and mix-blend-mode on that same element ends up blending against that buffer's transparent/black
  backdrop instead of the real page — difference(white, black) is just white unchanged, which is
  exactly the all-white result an actual screenshot showed. Splitting them onto parent/child means
  the child's filter output is fully resolved as ordinary content first, and only THEN does the
  parent's blend-mode composite that (already-flattened) result against the true page behind it.
*/
[data-home-style="glass"] .cursor-trail {
  position: fixed;
  inset: 0;
  pointer-events: none;
  z-index: 30;
  opacity: 0;
  mix-blend-mode: difference;
  transition: opacity 150ms ease;
}

[data-home-style="glass"] .cursor-trail.is-visible {
  opacity: 1;
}

[data-home-style="glass"] .cursor-trail-blob {
  position: absolute;
  inset: 0;
  filter: url(#cursor-goo);
}

[data-home-style="glass"] .cursor-trail-dot {
  position: absolute;
  top: 0;
  left: 0;
  border-radius: 50%;
  background: #fff;
  will-change: transform;
}

/*
  No CSS transition on any dot — site.js now moves every dot every animation frame (each one
  chasing the dot in front of it, see setupCursorTrail's frame() function), which is what actually
  keeps the trail's gaps bounded regardless of mouse speed. A CSS transition here would stack a
  SECOND, independent smoothing delay on top of the JS's own per-frame lerp, compounding into extra
  lag rather than helping — position is set directly, size is all that varies per dot now.
*/
[data-home-style="glass"] .cursor-trail-dot:nth-child(1) {
  width: 32px;
  height: 32px;
}

[data-home-style="glass"] .cursor-trail-dot:nth-child(2) {
  width: 26px;
  height: 26px;
}

[data-home-style="glass"] .cursor-trail-dot:nth-child(3) {
  width: 21px;
  height: 21px;
}

[data-home-style="glass"] .cursor-trail-dot:nth-child(4) {
  width: 16px;
  height: 16px;
}

[data-home-style="glass"] .cursor-trail-dot:nth-child(5) {
  width: 12px;
  height: 12px;
}

/* Hero ------------------------------------------------------------------------ */

.hero {
  min-height: calc(100svh - 71px);
  display: flex;
  align-items: center;
  padding-block: clamp(40px, 5vw, 72px) clamp(28px, 4vw, 48px);
  position: relative;
}

.hero > .container {
  width: 100%;
}

.hero-grid {
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  gap: 32px;
  position: relative;
}

.hero-copy {
  max-width: 760px;
  display: flex;
  flex-direction: column;
  align-items: center;
}

.hero-copy .eyebrow {
  justify-content: center;
}

.hero-title {
  margin-top: 20px;
  background: linear-gradient(120deg, var(--ink) 30%, var(--accent-2));
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
}

/*
  Spanish-only: "Webs con personalidad propia, rápidas de cargar y pensadas para durar." runs
  longer per-word than the English original and wraps to 4 lines instead of 3 at the base h1 clamp,
  pushing .hero-panel below the fold (.hero's min-height assumes the English 3-line height) — this
  is the "container leaves the screen a bit to the bottom" report, Spanish-only. Scoped to
  [lang="es"] so English is untouched. ~0.83x the base clamp (h1 { clamp(2.4rem, 3.2vw+1.4rem,
  4.4rem) } in base.css) was the smallest reduction that reliably gets back to 3 lines with a safe
  margin, verified with Playwright across 768–1920px viewport widths rather than assumed — below
  ~400px neither language actually fits in one screen (English already overflows there too), so
  that's an existing, unrelated tradeoff, not something this rule needs to chase.
*/
html[lang="es"][data-home-style="glass"] .hero-title {
  font-size: clamp(1.99rem, 2.66vw + 1.16rem, 3.65rem);
}

.hero-lede {
  margin-top: 22px;
  max-width: 58ch;
  color: var(--ink-soft);
  font-size: 1.08rem;
  text-shadow: 0 2px 16px rgba(0, 0, 0, 0.5);
}

.hero-actions {
  display: flex;
  justify-content: center;
  gap: 14px;
  margin-top: 24px;
  flex-wrap: wrap;
}

.hero-panel {
  width: 100%;
  padding: 24px;
  margin-top: 16px;
}

.hero-panel-top {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 8px;
  padding-bottom: 22px;
  margin-bottom: 22px;
  border-bottom: var(--border-w) solid var(--line);
}

.hero-panel-top span {
  font-family: var(--font-mono);
  font-size: 0.76rem;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--ink-faint);
}

.hero-panel-top strong {
  font-family: var(--font-display);
  font-size: 1.3rem;
}

.hero-panel-list {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 20px;
}

.hero-panel-list p {
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  gap: 10px;
  font-size: 0.92rem;
  color: var(--ink-soft);
}

.panel-index {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 30px;
  height: 30px;
  border-radius: 50%;
  background: var(--accent-soft);
  color: var(--accent-strong);
  font-family: var(--font-mono);
  font-weight: 700;
  font-size: 0.78rem;
}

@media (max-width: 720px) {
  .hero-panel-list {
    grid-template-columns: 1fr;
  }
}

/* Showcase ----------------------------------------------------------------------- */

.showcase-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 20px;
  margin-top: 32px;
}

.showcase-card {
  padding: 22px;
  border-radius: var(--radius-lg);
  transition: transform var(--dur-normal) var(--ease), box-shadow var(--dur-normal) var(--ease), border-color var(--dur-normal) var(--ease), background var(--dur-normal) var(--ease);
}

.showcase-card:hover {
  transform: translateY(-6px);
  border-color: var(--accent);
  background: rgba(20, 21, 32, 0.8);
  box-shadow: var(--shadow-lg), 0 0 40px rgba(139, 107, 255, 0.28);
}

/* A little color rotation across the six cards instead of one uniform violet, so the section
   reads as more than a single repeated tile. */
.showcase-card:nth-child(3n + 2):hover {
  border-color: var(--accent-2);
  box-shadow: var(--shadow-lg), 0 0 40px rgba(47, 216, 224, 0.28);
}
.showcase-card:nth-child(3n + 2) .service-icon {
  background: rgba(47, 216, 224, 0.16);
  color: var(--accent-2);
}
.showcase-card:nth-child(3n):hover {
  border-color: var(--accent-3);
  box-shadow: var(--shadow-lg), 0 0 40px rgba(255, 95, 184, 0.25);
}
.showcase-card:nth-child(3n) .service-icon {
  background: rgba(255, 95, 184, 0.16);
  color: var(--accent-3);
}

.service-icon {
  width: 30px;
  height: 30px;
  margin-bottom: 18px;
  padding: 8px;
  border-radius: 50%;
  background: var(--accent-soft);
  color: var(--accent-strong);
  fill: none;
  stroke: currentColor;
  stroke-width: 1.6;
  transition: transform var(--dur-normal) var(--ease), background var(--dur-normal) var(--ease);
}

.showcase-card:hover .service-icon,
.launch-item:hover .service-icon {
  transform: scale(1.1) rotate(-4deg);
}

.showcase-card p {
  color: var(--ink-soft);
  font-size: 0.94rem;
}

@media (max-width: 900px) {
  .showcase-grid {
    grid-template-columns: repeat(2, 1fr);
  }
}
@media (max-width: 600px) {
  .showcase-grid {
    grid-template-columns: 1fr;
  }
}

/* Process — glowing vertical timeline ------------------------------------------------- */

.process-layout {
  display: block;
}

.process-grid {
  position: relative;
  display: flex;
  flex-direction: column;
  gap: 34px;
  margin-top: 32px;
  padding-left: 52px;
}

/*
  Was one continuous line on .process-grid::before, sized top:10px to bottom:10px of the WHOLE grid.
  That height tracks the grid's total rendered height, not where the markers actually sit — since
  each step's marker sits near the top of its own step (top:-4px) while the step's real height is
  however tall its own h3+p text happens to be, the line's bottom edge landed wherever the LAST
  step's text ended, well past its own marker circle whenever that text was short enough to leave
  empty space below it (exactly the "line hanging under the rocket icon" report). Replaced with a
  separate short segment per step instead of one long line spanning arbitrary content height: each
  segment starts at ITS OWN step's marker center (top: 14px, i.e. the marker's top:-4px + half its
  36px height) and extends exactly `height: calc(100% + 34px)` — 100% of that step's own actual
  height (whatever it rendered to) plus the 34px gap to the next step — landing precisely on the
  NEXT marker's center regardless of how tall either step's text is. :not(:last-child) means the
  final step correctly gets no trailing segment at all.
*/
.process-step:not(:last-child)::before {
  content: "";
  position: absolute;
  left: -34px;
  top: 14px;
  height: calc(100% + 34px);
  width: 2px;
  background: linear-gradient(var(--accent), var(--accent-2));
  opacity: 0.5;
}

.process-step {
  position: relative;
  display: flex;
  gap: 20px;
  align-items: flex-start;
}

.step-marker {
  position: absolute;
  left: -52px;
  top: -4px;
  width: 36px;
  height: 36px;
  border-radius: 50%;
  background: var(--surface);
  border: 2px solid var(--accent);
  box-shadow: 0 0 14px var(--accent);
  display: flex;
  align-items: center;
  justify-content: center;
}

.step-icon {
  width: 16px;
  height: 16px;
  color: var(--accent);
}

.step-index {
  position: absolute;
  font-size: 0;
}

.process-step h3 {
  font-size: 1.05rem;
  text-shadow: 0 2px 12px rgba(0, 0, 0, 0.45);
}

.process-step p {
  color: var(--ink-soft);
  font-size: 0.94rem;
  max-width: 56ch;
  text-shadow: 0 2px 12px rgba(0, 0, 0, 0.45);
}

/* Launch-ready ------------------------------------------------------------------------- */

.launch-grid {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 22px;
  margin-top: 32px;
}

.launch-item {
  padding: 22px;
  border-radius: var(--radius-lg);
  display: flex;
  gap: 18px;
  align-items: flex-start;
  transition: transform var(--dur-normal) var(--ease), box-shadow var(--dur-normal) var(--ease), border-color var(--dur-normal) var(--ease), background var(--dur-normal) var(--ease);
}

.launch-item:hover {
  transform: translateY(-4px);
  border-color: var(--accent-2);
  background: rgba(20, 21, 32, 0.8);
  box-shadow: var(--shadow-md), 0 0 34px rgba(47, 216, 224, 0.22);
}

.launch-item:nth-child(3n):hover {
  border-color: var(--accent-3);
  box-shadow: var(--shadow-md), 0 0 34px rgba(255, 95, 184, 0.22);
}

.launch-item .service-icon {
  margin-bottom: 0;
  flex-shrink: 0;
}

@media (max-width: 720px) {
  .launch-grid {
    grid-template-columns: 1fr;
  }
}

/*
  Phone-only: title and body stacked full-width instead of side by side. .launch-item's icon/h3/p are
  three flex siblings in a row with no explicit width on h3 or p — once .launch-grid itself is down
  to a single column (≤720px, matching the breakpoint right above), after the icon takes its own
  space h3 and p split what's left between them (shrinking roughly in proportion to their own content
  length, not stacking), so a short title like "Search-ready on day one" got squeezed into a ~100-150px
  column and wrapped into three cramped, hyphen-breaking lines right next to a slightly-wider
  body-text column doing the same — confirmed by measuring both columns' actual rendered width across
  the whole single-column range (390 through 720px), not just eyeballing one screenshot: the cramped
  wrapping was present at every width in that range, which is why this uses the exact same 720px
  breakpoint as the grid's own single-column switch, not a narrower "phone-only" guess — the two are
  the same underlying condition. Switching to a column direction here lets h3/p each use the card's
  full width to wrap in, which is dramatically easier to read; align-self on the icon keeps IT compact
  and left-aligned rather than also stretching to full width like h3/p now do.
*/
@media (max-width: 720px) {
  .launch-item {
    flex-direction: column;
    align-items: stretch;
  }

  .launch-item .service-icon {
    align-self: flex-start;
  }
}

/* Pricing ------------------------------------------------------------------------------- */

/*
  This was accidentally `display: flex` with no flex-direction (defaults to row), while every
  descendant rule below assumed a centered, stacked layout (text-align: center, margin-inline: auto,
  a small margin-top to sit below the heading) — so in reality it rendered as an unintentional
  side-by-side row with the card mis-aligned against the heading text. Made the side-by-side layout
  intentional instead (matching Studio's approach) rather than reverting to stacked.
*/
.pricing-layout {
  display: grid;
  grid-template-columns: 1fr 0.85fr;
  gap: 48px;
  align-items: center;
}

/*
  margin-inline: auto is load-bearing, not decorative — .pricing-layout collapses to a single
  1fr column below 900px, and once the viewport is wider than this card's own 520px max-width (a
  foldable phone unfolded, or any tablet-ish width), the card doesn't stretch to fill that column,
  but nothing was centering it in the leftover space either, so it defaulted to sitting flush against
  the column's own start edge with all the extra room visibly empty on the right — confirmed via an
  actual user screenshot, not assumed. Narrower phones never showed this, since the available width
  there is already less than 520px, so the card just fills 100% of it either way.
*/
.pricing-card {
  width: 100%;
  max-width: 520px;
  margin-inline: auto;
  padding: 26px;
  text-align: center;
  transition: border-color var(--dur-normal) var(--ease), box-shadow var(--dur-normal) var(--ease);
}

@media (max-width: 900px) {
  .pricing-layout {
    grid-template-columns: 1fr;
  }
}

.pricing-card:hover {
  border-color: var(--accent);
  box-shadow: var(--shadow-lg), 0 0 50px rgba(139, 107, 255, 0.22);
}

.price-line {
  flex-direction: column;
  gap: 8px;
  padding-bottom: 24px;
  margin-bottom: 24px;
  border-bottom: var(--border-w) solid var(--line);
}

/*
  Grid instead of the inherited text-align: center this used to just rely on: with .price-old and
  the big <strong> price sitting side by side as plain inline content, centering the whole run
  visually shifts the big number off-center — it's pulled toward the smaller €300 sitting to its
  left, so the number that actually matters ends up ~21px right of the card's true center (measured).
  1fr/auto/1fr puts <strong> in a column that's genuinely centered on its own, with .price-old
  right-aligned in the mirrored column to its left so it still reads as sitting right next to it.
*/
.price-values {
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: baseline;
}

.price-values strong {
  grid-column: 2;
  font-family: var(--font-display);
  font-size: 3rem;
  background: linear-gradient(120deg, var(--accent), var(--accent-2));
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
}

.price-old {
  grid-column: 1;
  justify-self: end;
  margin-right: 8px;
  color: var(--ink-faint);
  text-decoration: line-through;
}

.pricing-card .check-list {
  display: inline-flex;
  flex-direction: column;
  gap: 14px;
  text-align: left;
}

/* About brief ------------------------------------------------------------------------------ */

.about-brief-layout {
  display: flex;
  align-items: center;
  gap: 40px;
  padding: 28px;
  border-radius: var(--radius-lg);
  background: var(--surface-elevated);
  backdrop-filter: blur(20px);
  -webkit-backdrop-filter: blur(20px);
  border: var(--border-w) solid var(--line);
}

.about-brief-mark {
  flex-shrink: 0;
  width: 96px;
  filter: brightness(1.4);
}

.about-brief-copy {
  flex: 1;
}

.about-brief-copy p {
  color: var(--ink-soft);
  margin-top: 12px;
}

.about-brief-facts {
  display: flex;
  gap: 28px;
  flex-shrink: 0;
}

.about-brief-facts p {
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.about-brief-facts strong {
  font-family: var(--font-display);
  font-size: 1.6rem;
  background: linear-gradient(120deg, var(--accent), var(--accent-2));
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
}

.about-brief-facts span {
  font-size: 0.84rem;
  color: var(--ink-soft);
  max-width: 16ch;
}

@media (max-width: 900px) {
  .about-brief-layout {
    display: block;
    gap: 0;
  }

  .about-brief-mark {
    float: right;
    width: 64px;
    margin: 0 0 16px 16px;
  }

  .about-brief-copy {
    margin-bottom: 24px;
  }

  .about-brief-facts {
    clear: both;
  }
}

/*
  Same structural issue and fix as .cta-band in base.css: this element is both `.container` and the
  thing carrying its own visible frosted-glass background (`<div class="container about-brief-
  layout">`), and this style is the only one of the five that gives .about-brief-layout a background
  of its own (every other style keeps it as a plain, invisible layout wrapper) — so this specific fix
  belongs here, not in the shared file. Below ~1180px, .container's own max-width isn't yet creating
  real margin via its auto centering, so the visible card ran flush to the viewport edges with
  nothing but its own internal 28px padding — confirmed via an actual screenshot on a wide
  (foldable-unfolded-width) phone.
*/
@media (max-width: 1180px) {
  .about-brief-layout {
    width: auto;
    margin-inline: var(--container-pad);
  }
}

/* Work examples ------------------------------------------------------------------------------ */

.work-grid {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 18px;
  margin-top: 32px;
}

.work-card {
  display: flex;
  flex-direction: column;
  gap: 10px;
  padding: 20px;
  border-radius: var(--radius-lg);
  position: relative;
  transition: border-color var(--dur-work-grow) var(--ease), background var(--dur-work-grow) var(--ease), box-shadow var(--dur-work-grow) var(--ease);
}

.work-card:hover {
  border-color: var(--accent);
  background: rgba(20, 21, 32, 0.8);
  box-shadow: 0 0 30px rgba(139, 107, 255, 0.25);
}

.work-card:nth-child(even):hover {
  border-color: var(--accent-2);
  box-shadow: 0 0 30px rgba(47, 216, 224, 0.25);
}

.work-number {
  font-family: var(--font-mono);
  color: var(--accent-2);
  font-size: 0.78rem;
}

/*
  Small always-visible screenshot preview, replacing the old arrow icon in the same bottom-anchored
  slot (margin-top: auto). Fixed aspect-ratio + object-fit: cover so all 4 screenshots (slightly
  different native sizes) crop to a consistent shape regardless of source dimensions.
*/
.work-preview {
  display: block;
  margin-top: auto;
  border-radius: var(--radius-md);
  overflow: hidden;
  border: var(--border-w) solid var(--line);
}

.work-preview img {
  display: block;
  width: 100%;
  height: auto;
  aspect-ratio: 1400 / 722;
  object-fit: cover;
}

/*
  Grow-on-hover (desktop/mouse, via :hover) or grow-on-focus (touch, via the ".is-work-focused" class
  site.js's setupWorkCardFocus adds to whichever card is scroll-centered — see the comment there).
  Both triggers share the exact same visual rule below; only what turns it on differs per device.

  This base setup block is deliberately NOT gated behind (hover: hover) — it has to apply on touch
  devices too, since .is-work-focused needs the same transform-origin/transition/z-index scaffolding
  :hover does. Only the TRIGGERS themselves (the :hover pseudo-class, and the bigger desktop scale
  tier) are hover/width-gated further down.

  transform-origin: 50% 0% (top-center) is what makes scale() grow the card down, left, and right
  from a fixed top edge instead of centered growth that would also creep upward — exactly the "not
  up" the card was asked to respect.
*/
.work-grid {
  overflow: visible;
}

.work-card {
  --work-scale: 1.08;
  z-index: 1;
  transform: scale(1);
  transform-origin: 50% 0%;
  transition: transform var(--dur-work-grow) var(--ease), border-color var(--dur-work-grow) var(--ease), background var(--dur-work-grow) var(--ease), box-shadow var(--dur-work-grow) var(--ease);
}

.work-card:hover,
.work-card.is-work-focused {
  transform: scale(var(--work-scale));
  z-index: 2;
}

/*
  Counter-scaling the title against the card's own grow so it only ends up moderately bigger instead
  of growing in direct proportion to the whole card, per spec.
*/
.work-card:hover .work-title,
.work-card.is-work-focused .work-title {
  display: inline-block;
  transform: scale(0.78);
  transform-origin: 0% 0%;
}

/*
  Desktop gets a notably bigger scale from 901px up (matching the 4-column breakpoint) — a genuinely
  dramatic grow with the screenshot actually readable. Below that (a resized/narrow desktop window,
  still hover-capable) and on touch, --work-scale stays at the gentler 1.08 default above.
*/
@media (hover: hover) and (pointer: fine) and (min-width: 901px) {
  .work-card {
    --work-scale: 1.45;
  }
}

/*
  Neighbor push, desktop 4-across layout only — scoped to the same min-width as the 4-column grid
  itself, since :has(~ hover)/~ hover reason purely in DOM order, and DOM order only lines up with
  true visual left/right neighbors while all 4 cards share a single row. Below that width the grid
  wraps to 2 or 1 columns, where a card before/after in DOM order can sit in a different row entirely
  (e.g. diagonally adjacent, not beside it) — pushing it would look wrong, so this stays desktop-only
  rather than guessing at per-breakpoint nth-child math for a rarely-hit case (a hover-capable device
  at a narrow window width).

  :has(~ .work-card:hover) — general sibling, not adjacent (+) — is deliberate: it matches ANY card
  that has a hovered card somewhere after it, not just the one immediately before. The first version
  used :has(+ hover) (immediate-only), which meant hovering card 1 correctly pushed all 3 later cards
  right (they're all "immediately or generally after" it either way), but hovering card 3 only pushed
  card 2 left, not card 1 too — card 1 sits two cards away, not adjacent, so it never matched. That
  read as "some cards push everything, others only push their one neighbor," confirmed directly by
  hovering each of the 4 cards in turn and comparing which siblings actually moved. :has(~ hover) fixes
  it by matching every earlier card regardless of distance, symmetric with how ~ .work-card already
  matched every later card regardless of distance.

  22.5% (not a fixed px value) is the exact same growth-per-side fraction as --work-scale: 1.45 above
  (a 45% scale grows 22.5% of the card's own width on each side), expressed as a percentage so it
  stays correctly proportional at any viewport width and so the push always matches however big the
  grow currently is — a fixed px value that doesn't track the scale is what let a growing card
  visually swallow/overlap the neighbor it had just pushed in an earlier version.
*/
@media (hover: hover) and (pointer: fine) and (min-width: 901px) {
  .work-card:has(~ .work-card:hover) {
    transform: translateX(-22.5%);
  }

  .work-card:hover ~ .work-card {
    transform: translateX(22.5%);
  }
}

@media (max-width: 900px) {
  .work-grid {
    grid-template-columns: repeat(2, 1fr);
  }
}
@media (max-width: 560px) {
  .work-grid {
    grid-template-columns: 1fr;
  }
}

/* FAQ ------------------------------------------------------------------------------------------ */

.faq-list {
  margin-top: 26px;
  display: flex;
  flex-direction: column;
  gap: 14px;
}

.faq-item {
  border-radius: var(--radius-md);
  padding: 18px 22px;
  transition: border-color var(--dur-normal) var(--ease), background var(--dur-normal) var(--ease);
}

.faq-item:hover {
  border-color: var(--line-strong);
  background: rgba(20, 21, 32, 0.78);
}

.faq-item[open] {
  border-color: var(--accent);
}

.faq-item summary {
  cursor: pointer;
  list-style: none;
  position: relative;
  padding-right: 30px;
  font-family: var(--font-display);
  font-weight: 600;
}

.faq-item summary::-webkit-details-marker {
  display: none;
}

.faq-item summary::after {
  content: "";
  position: absolute;
  right: 2px;
  top: 4px;
  width: 10px;
  height: 10px;
  border-right: 2px solid var(--accent);
  border-bottom: 2px solid var(--accent);
  transform: rotate(45deg);
  transition: transform var(--dur-normal) var(--ease);
}

.faq-item[open] summary::after {
  transform: rotate(-135deg);
  top: 8px;
}

.faq-item p {
  margin-top: 12px;
  color: var(--ink-soft);
  font-size: 0.95rem;
}

/* Final CTA --------------------------------------------------------------------------------------- */

.final-cta {
  /* Top only, tightened slightly per request (faq → start-a-message gap); bottom stays as it was. */
  padding-top: clamp(30px, 3.4vw, 48px);
  padding-bottom: clamp(32px, 5vw, 64px);
}

/*
  A deliberate break from the glass/translucent pattern used everywhere else — the closing CTA is
  the one moment that should read as a confident, solid statement rather than blend into the
  atmosphere behind it, so it gets a solid gradient block instead of a frosted card.
*/
.cta-band {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 28px;
  flex-wrap: wrap;
  padding: 40px;
  border-radius: var(--radius-lg);
  background: linear-gradient(135deg, #2a1f5e, #123a44);
  border: var(--border-w) solid var(--line-strong);
  position: relative;
  overflow: hidden;
}

/*
  pointer-events: none on both — these are purely decorative glow circles, but a generated-content
  box is hit-testable by default regardless of how transparent/blurred it looks, and their full
  rectangles (380x380 / 260x260) are large enough to sit on top of the "Contact us" button in this
  same band. Without this, most of the button's own area silently dispatched clicks to the parent
  .cta-band div instead — confirmed via elementFromPoint at the button's center/left/top/bottom, only
  its rightmost sliver (outside both circles' boxes) ever actually hit the button itself. Every other
  purely-decorative element elsewhere in this codebase (.deco-blobs, .cursor-trail, .tap-signal) already
  gets this; these two were simply missed.
*/
.cta-band::before {
  content: "";
  position: absolute;
  width: 380px;
  height: 380px;
  right: -120px;
  top: -160px;
  background: radial-gradient(circle, var(--accent), transparent 70%);
  opacity: 0.55;
  filter: blur(10px);
  pointer-events: none;
}

.cta-band::after {
  content: "";
  position: absolute;
  width: 260px;
  height: 260px;
  left: -80px;
  bottom: -120px;
  background: radial-gradient(circle, var(--accent-2), transparent 70%);
  opacity: 0.4;
  filter: blur(10px);
  pointer-events: none;
}

.cta-band .eyebrow {
  color: var(--accent-2);
}

.cta-band h2,
.cta-band p {
  position: relative;
}

.cta-band h2 {
  margin-top: 8px;
}

.cta-band p {
  margin-top: 8px;
  color: rgba(255, 255, 255, 0.82);
}
