/* ==========================================================================
   What we help you achieve — Figma frame-y 3451→4563 (1112 tall)
   Absolute 1440 canvas: hairline, aura rings, ball crest, 3x2 card grid.
   The comp's stripe field (91:6) was deleted in the redesign.
   ========================================================================== */

.gw-achieve {
  position: relative;
  background: var(--gw-white);
  overflow: clip;
  container-type: inline-size;
}

.gw-achieve__stage {
  position: relative;
  width: 100%;
  max-width: 1440px;
  margin-inline: auto;
  height: calc(1112 * var(--u));
  --u: min(1px, calc(100cqw / 1440));
}
.gw-achieve__stage > * { position: absolute; }

/* ---- ball crest (91:16), faded out downward as in the comp --------------- */
.gw-achieve__crest {
  top: calc(55 * var(--u)); left: calc(129 * var(--u));
  width: calc(1184 * var(--u)); height: calc(306 * var(--u));
  overflow: hidden;
  z-index: 1;
  /* the comp holds the ball at full strength through the upper half of the
     crest and only then lets go — fading from the very top thinned it out
     exactly where the dimples have the most to say */
  -webkit-mask-image: linear-gradient(180deg, #000 0%, #000 42%, transparent 100%);
          mask-image: linear-gradient(180deg, #000 0%, #000 42%, transparent 100%);
}
/* The ball itself. It was a pre-rendered sprite film: 32 ray-traced frames
   stepped through with steps(), which meant a 740x7200 texture upscaled 1.25x
   to fit (hence soft) and a repaint of that whole layer on every step (hence
   the stutter). It is drawn in CSS now — a dimple lattice on a round, lit body,
   moved with translate3d, so it is one composited layer that never repaints and
   is resolution-independent. The element is the WHOLE 926 sphere; the crest box
   above clips it to the cap the comp shows.
   --pitch divides 926 a whole number of times (18), so translating the skin by
   exactly one sphere-width lands the lattice back on itself and the loop is
   invisible. */
.gw-achieve__globe {
  position: absolute;
  left: calc(111 * var(--u));
  top: calc(38 * var(--u));
  width: calc(926 * var(--u));
  height: calc(926 * var(--u));
  border-radius: 50%;
  overflow: hidden;
  isolation: isolate;
  /* the crest's own top-to-bottom fade is what thins the ball out; a second
     blanket opacity on top of it just made the lattice disappear */
  background: #fcfcfc;
  --pitch: calc(926 * var(--u) / 22);
  --dimple: rgb(0 0 0 / 0.21);
}

/* The GPU ball. It covers only the band the crest actually shows — the top 268
   of the 926 sphere — so nothing is rendered where nothing is seen. The shader
   draws its own silhouette and its own edge feather, so it needs no clip. */
.gw-achieve__globe-gl {
  position: absolute;
  top: 0;
  left: 0;
  display: block;
  width: 100%;
  height: calc(270 * var(--u));
}
/* once the canvas is up, the CSS approximation underneath is dead weight */
.gw-achieve__globe.is-gl { background: none; }
.gw-achieve__globe.is-gl .gw-achieve__globe-skin,
.gw-achieve__globe.is-gl .gw-achieve__globe-lit { display: none; }

/* The lattice, laid out by the projection rather than as a flat grid — a plain
   repeating grid clipped to a circle reads as wallpaper on a disc, which is what
   this looked like on the first pass.

   One background layer per latitude, each repeating along x only. Two things
   vary with latitude phi, and between them they are the whole dome:

     y = R(1 - sin phi)     rows crowd together toward the crown
     h = H0 * cos phi       we see the surface edge-on at the pole and square on
                            at the equator, so a round dimple projects as a
                            flatter and flatter ellipse the higher it sits

   The horizontal pitch is the one thing that stays constant. Rows nearer the
   pole hold fewer dimples but are drawn across a proportionally narrower disc,
   and the two cancel — which is why a real golf ball's dimples look evenly
   spaced across its face however far up you look. Alternate rows are offset half
   a pitch for the brick packing. */
.gw-achieve__globe-skin {
  position: absolute;
  top: 0;
  left: 0;
  width: 200%;            /* two tiles, so the wrap-around is seamless */
  height: 100%;
  background-image:
    radial-gradient(ellipse at 50% 50%, var(--dimple) 0 26%, transparent 60%),
    radial-gradient(ellipse at 50% 50%, var(--dimple) 0 26%, transparent 60%),
    radial-gradient(ellipse at 50% 50%, var(--dimple) 0 26%, transparent 60%),
    radial-gradient(ellipse at 50% 50%, var(--dimple) 0 26%, transparent 60%),
    radial-gradient(ellipse at 50% 50%, var(--dimple) 0 26%, transparent 60%),
    radial-gradient(ellipse at 50% 50%, var(--dimple) 0 26%, transparent 60%),
    radial-gradient(ellipse at 50% 50%, var(--dimple) 0 26%, transparent 60%),
    radial-gradient(ellipse at 50% 50%, var(--dimple) 0 26%, transparent 60%),
    radial-gradient(ellipse at 50% 50%, var(--dimple) 0 26%, transparent 60%),
    radial-gradient(ellipse at 50% 50%, var(--dimple) 0 26%, transparent 60%),
    radial-gradient(ellipse at 50% 50%, var(--dimple) 0 26%, transparent 60%);
  background-size:
    var(--pitch) calc(4.3 * var(--u)),
    var(--pitch) calc(12.7 * var(--u)),
    var(--pitch) calc(20.9 * var(--u)),
    var(--pitch) calc(28.7 * var(--u)),
    var(--pitch) calc(36.0 * var(--u)),
    var(--pitch) calc(42.5 * var(--u)),
    var(--pitch) calc(48.2 * var(--u)),
    var(--pitch) calc(53.0 * var(--u)),
    var(--pitch) calc(56.7 * var(--u)),
    var(--pitch) calc(59.4 * var(--u)),
    var(--pitch) calc(60.9 * var(--u));
  background-position:
    0 calc(-1.0 * var(--u)),
    calc(var(--pitch) / 2) calc(3.8 * var(--u)),
    0 calc(17.5 * var(--u)),
    calc(var(--pitch) / 2) calc(39.8 * var(--u)),
    0 calc(70.4 * var(--u)),
    calc(var(--pitch) / 2) calc(108.7 * var(--u)),
    0 calc(153.8 * var(--u)),
    calc(var(--pitch) / 2) calc(205.0 * var(--u)),
    0 calc(261.2 * var(--u)),
    calc(var(--pitch) / 2) calc(321.3 * var(--u)),
    0 calc(384.2 * var(--u));
  background-repeat: repeat-x, repeat-x, repeat-x, repeat-x, repeat-x, repeat-x, repeat-x, repeat-x, repeat-x, repeat-x, repeat-x;
}

/* Volume and light, painted over the lattice and never moving: the highlight
   stays put while the surface turns under it, which is what sells the spin. */
.gw-achieve__globe-lit {
  position: absolute;
  inset: 0;
  border-radius: 50%;
  background:
    /* key light, upper left as in the comp — it stays put while the surface
       turns under it, which is what sells the spin */
    radial-gradient(circle at 38% 15%, rgb(255 255 255 / 0.58) 0%, rgb(255 255 255 / 0.22) 26%, rgb(255 255 255 / 0) 48%),
    /* limb wash. Toward the edge the surface turns away from us and the dimples
       crowd into nothing; washing them out there stands in for a foreshortening
       a repeating background cannot do, and it is how the comp's edge dissolves
       into the page rather than ending on a rim. */
    radial-gradient(circle at 50% 50%, rgb(255 255 255 / 0) 0 88%, rgb(255 255 255 / 0.35) 95%, rgb(255 255 255 / 0.9) 100%);
}

@keyframes gw-globe-spin {
  /* -50% of a 200%-wide skin is exactly one sphere width = 18 whole cells */
  from { transform: translate3d(0, 0, 0); }
  to   { transform: translate3d(-50%, 0, 0); }
}
.gw-motion .gw-achieve__globe-skin {
  animation: gw-globe-spin 7s linear infinite;
  will-change: transform;
  backface-visibility: hidden;
}

/* ---- heading (91:130) ---------------------------------------------------- */
.gw-achieve__title {
  top: calc(273 * var(--u)); left: calc(85 * var(--u));
  width: calc(1270 * var(--u));
  display: flex; flex-direction: column;
  text-align: center;
  font-family: var(--gw-font-display);   /* char overrides make this Cal Sans 400 */
  font-weight: 400;
  font-size: calc(36 * var(--u));
  line-height: calc(50.4 * var(--u));
  z-index: 2;
}
.gw-achieve__title-a { color: var(--gw-black); }
.gw-achieve__title-b { color: var(--gw-violet); }


/* ---- card grid (229:76) — 1052 wide, 337.33x302.5 cards ------------------
   Columns are 1fr rather than a literal 337.33 so the three always add back up
   to the comp's 1052 without rounding drift.                                */
.gw-achieve__grid {
  top: calc(433 * var(--u)); left: calc(195 * var(--u));
  width: calc(1052 * var(--u));
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  column-gap: calc(20 * var(--u));
  row-gap: calc(21 * var(--u));
  z-index: 4;
}

.gw-achieve__card {
  position: relative;
  height: calc(302.5 * var(--u));
  padding: calc(25 * var(--u));
  /* inset shadow, not a border: Figma draws the stroke inside the 337.33 frame,
     so a real border would steal 2px and rewrap every description */
  box-shadow: inset 0 0 0 1px var(--gw-line);
  background: var(--gw-white);
  display: flex;
  flex-direction: column;
  /* title rides the top, description sits on the bottom padding edge — the
     comp positions every description against the card's foot, not against the
     end of its title, so cards with short titles open a gap in the middle */
  justify-content: space-between;
  overflow: hidden;
  transition: background-color var(--gw-dur-slow) var(--gw-ease);
}
/* the comp draws card 1 violet purely to document this state; every card rests
   white and lifts into it on hover */
.gw-achieve__card:hover,
.gw-achieve__card:focus-within { background: var(--gw-violet); }

/* The supplied glyphs are violet artwork, but the comp paints the watermark as
   the card ground darkened to exactly 80% — measured (87,32,174) over
   (109,40,217). That is black at 20%, so the glyph is flattened to black and
   carried at 0.2; aspect ratios differ between the six, hence `contain`. */
.gw-achieve__glyph {
  position: absolute;
  top: calc(106.5 * var(--u)); left: calc(142 * var(--u));
  width: calc(170 * var(--u)); height: calc(171 * var(--u));
  object-fit: contain;
  filter: brightness(0);
  opacity: 0;
  transition: opacity var(--gw-dur-slow) var(--gw-ease);
  pointer-events: none;
}

.gw-achieve__card-title {
  position: relative;
  font-family: var(--gw-font-display);
  font-weight: 400;
  font-size: calc(32 * var(--u));
  line-height: calc(42 * var(--u));
  color: var(--gw-black);
  transition: color var(--gw-dur-slow) var(--gw-ease);
}
.gw-achieve__card-desc {
  position: relative;
  font-size: calc(16 * var(--u));
  line-height: calc(22.4 * var(--u));
  color: var(--gw-black);
  transition: color var(--gw-dur-slow) var(--gw-ease);
}

/* the black→violet wash, clipped to the glyphs. --mid is where the comp puts
   the hand-off on that card; the 18% skirt either side is what makes it read
   as a wash rather than a hard two-tone split. */
.gw-achieve__card-title {
  background-image: linear-gradient(90deg,
    #000000 calc(var(--mid, 50%) - 18%),
    #6D28D9 calc(var(--mid, 50%) + 18%));
  -webkit-background-clip: text;
  background-clip: text;
  -webkit-text-fill-color: transparent;
  /* background-clip:text paints only inside the box, so a descender hanging
     below a tight line-height gets sliced off. Extend the box downward and take
     the space straight back so layout is untouched. */
  padding-bottom: 0.24em;
  margin-bottom: -0.24em;
}

/* violet ground: light title, white body, watermark fades up */
.gw-achieve__card:hover .gw-achieve__card-title,
.gw-achieve__card:focus-within .gw-achieve__card-title {
  background-image: none;
  color: var(--gw-violet-200);
  -webkit-text-fill-color: var(--gw-violet-200);
}
.gw-achieve__card:hover .gw-achieve__card-desc,
.gw-achieve__card:focus-within .gw-achieve__card-desc { color: var(--gw-white); }
.gw-achieve__card:hover .gw-achieve__glyph,
.gw-achieve__card:focus-within .gw-achieve__glyph { opacity: 0.2; }

/* ---- responsive ---------------------------------------------------------- */
@media (max-width: 1023px) {
  .gw-achieve__stage { height: auto; --u: 1px; padding: 56px var(--gw-gutter) 64px; }
  .gw-achieve__stage > * { position: static; }
  .gw-achieve__crest { width: 100%; height: auto; max-height: 200px; margin-bottom: 24px; }
  .gw-achieve__title { width: 100%; font-size: 30px; line-height: 40px; margin-bottom: 32px; }
  .gw-achieve__grid { width: 100%; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 20px; }
  .gw-achieve__card { height: auto; min-height: 260px; gap: 24px; }
  .gw-achieve__glyph { position: absolute; top: auto; bottom: 12px; right: 12px; left: auto; width: 120px; height: 120px; }
}

@media (max-width: 640px) {
  .gw-achieve__grid { grid-template-columns: minmax(0, 1fr); }
  .gw-achieve__title { font-size: 24px; line-height: 32px; }
  .gw-achieve__card-title { font-size: 26px; line-height: 34px; }
}


/* ==========================================================================
   Motion — globe drift on the crest, ripple on the aura rings.
   Gated on .gw-motion; reduced-motion users get the static comp.
   ========================================================================== */

/* The comp's aura is static — it is a drawn decoration, not a wave.

   The ripple is four circles concentric with the ball, starting on its crown
   + 30 and swelling outward. Two things keep it calm:

   - it is painted BEHIND the crest (z-index 0 against the crest's 1), so the
     ball occludes the lower arcs and the wave reads as rising out from behind
     it rather than crossing over it;
   - there is only ~93 of runway between the crown and the top of the section,
     so a mask dissolves it well before either edge — nothing is ever seen being
     clipped by the section boundary, and nothing reaches the heading. */
.gw-achieve__ripples {
  top: 0; left: 0;
  width: calc(1440 * var(--u)); height: calc(1112 * var(--u));
  z-index: 0;
  pointer-events: none;
  /* 0-67 dissolve at the section edge, 67-167 full, gone by 233 — the heading
     starts at 273, so the wave never reaches it */
  -webkit-mask-image: linear-gradient(180deg,
    transparent 0%, #000 6%, #000 15%, transparent 21%);
          mask-image: linear-gradient(180deg,
    transparent 0%, #000 6%, #000 15%, transparent 21%);
}
.gw-achieve__ripple { opacity: 0; fill: none; }
@keyframes gw-ripple {
  0%   { transform: scale(1);    opacity: 0; }
  22%  { opacity: 0.16; }
  100% { transform: scale(1.42); opacity: 0; }
}
.gw-motion .gw-achieve__ripple {
  transform-box: view-box;
  transform-origin: 703px 556px;   /* centre of the 926 sphere behind the crest */
  animation: gw-ripple 9s cubic-bezier(0.3, 0.5, 0.35, 1) infinite;
  animation-delay: calc(var(--i) * 2.25s);
}
