/* =========================================================================
   template-parts/sections/section-feature-grid.php
   Moved out of the partial's inline <style id="es-feature-grid-css"> on the owner's
   instruction, 10 Sep 2026. en_print_css() (inc/css-loader.php) prints this
   file's <link> where the <style> used to be, once per page, so every page
   that renders this section shares this one file.
   ========================================================================= */

/* ── Author-controlled line breaks ─────────────────────────
   Copy in this section carries a <br> wherever the design pins
   a wrap. Those breaks are drawn against the desktop column
   width, so below it they are suppressed and the text wraps to
   whatever width it actually has. A break frozen at desktop
   would otherwise strand one or two words on a phone line.

   Scoped to the section, so it only governs breaks an editor
   put in this component's copy. */
.es-fgrid br { display: none; }

@media (min-width: 992px) {
  .es-fgrid br { display: inline; }
}

.es-fgrid__grid {
  display: grid;
  gap: var(--gap-fluid-md);
  grid-template-columns: 1fr;
}

@media (min-width: 768px) {
  .es-fgrid__grid--2 { grid-template-columns: repeat(2, 1fr); }
  .es-fgrid__grid--3 { grid-template-columns: repeat(2, 1fr); }
  .es-fgrid__grid--4 { grid-template-columns: repeat(2, 1fr); }
}

@media (min-width: 992px) {
  .es-fgrid__grid--3 { grid-template-columns: repeat(3, 1fr); }
  .es-fgrid__grid--4 { grid-template-columns: repeat(4, 1fr); }
}

/* ── Horizontal card ───────────────────────────────────────
   Icon parked on the left with a hairline divider, copy on the
   right. Keeps a wide card from leaving a lake of empty space
   under a centred icon. */
/* Doubled class so it beats the base card's `flex-direction: column`
   regardless of which block comes first in this stylesheet. */
.es-fgrid__card.es-fgrid__card--row {
  flex-direction: row;
  align-items: flex-start;
  gap: var(--space-5);
}

.es-fgrid__card--row .es-fgrid__icon {
  flex-shrink: 0;
  margin-bottom: 0;
}

.es-fgrid__card--row .es-fgrid__body { flex: 1 1 auto; min-width: 0; }

/* ── Row card, vertically centred ──────────────────────────
   `row_align => 'center'`. For a body that is one short heading
   and nothing else: against a 72px ring a top-aligned label
   reads as though it has slipped upwards, and the taller the
   row's tallest card the worse it gets, because every card in
   a grid row stretches to that height.

   The trailing margin under the heading goes with it. It is
   there to open a gap before the paragraph that follows, and
   on a card where the heading IS the content it is just dead
   space at the bottom of the box. `:last-child` rather than a
   blanket reset, so a centred row card that DOES carry copy
   keeps the gap.

   Doubled class, for the same reason the `--row` rule above is
   doubled: it has to beat that rule's own `align-items`, and
   that one is already at two classes. */
.es-fgrid__card--row.es-fgrid__card--rowmid { align-items: center; }
.es-fgrid__card--rowmid .es-fgrid__body > h3:last-child { margin-bottom: 0; }

/* The row rule further up already says a row card's mark carries
   no bottom margin, but `--compact.--roundicon` further DOWN this
   file restates the margin at three classes and quietly wins. Top
   aligned that costs nothing, because the margin sits under a mark
   that is already at the top of the card; centred it throws the
   mark 8px above true centre. Four classes so it wins on
   specificity rather than on where it happens to sit in the file,
   and scoped to `--rowmid` so no existing caller moves. */
.es-fgrid__card.es-fgrid__card--row.es-fgrid__card--rowmid .es-fgrid__icon {
  margin-bottom: 0;
}

/* The wrapper means the card's own `> p` rule no longer reaches the
   copy, so restate it one level in. */
.es-fgrid__card--row .es-fgrid__body > p {
  margin: 0;
  color: var(--text-body);
  font-size: var(--fs-body-sm);
  line-height: var(--lh-body);
}

.es-fgrid__card--row.es-fgrid__card--lg .es-fgrid__body > p { font-size: var(--fs-body); }

@media (min-width: 576px) {
  .es-fgrid__card.es-fgrid__card--row {
    gap: var(--space-5);
    padding: var(--space-6) var(--space-6) var(--space-6) var(--space-5);
  }

  /* Icon in a thin brand ring rather than the stacked card's
     filled square, with a hairline rule separating it from the
     copy. */
  .es-fgrid__card--row .es-fgrid__icon {
    width: 72px;
    height: 72px;
    margin-bottom: 0;
    border: 1px solid var(--brand-100);
    border-radius: var(--radius-full);
    background: none;
    transition: border-color var(--duration-normal) var(--ease-out),
                transform var(--duration-normal) var(--ease-out);
  }

  .es-fgrid__card--row .es-fgrid__icon img { width: 40px; height: 40px; }
}

/* ── Glow hover ────────────────────────────────────────────
   Alternative to the lift, for cards that lead with an icon:
   the icon ring lights up and the card rests on a tighter
   brand-tinted shadow. It opts out of the default's corner wash
   so the two hovers stay distinct, and because a lit icon plus
   a wash behind it is two effects competing in one card.

   Doubled class throughout so these beat the base card's wash
   and lift rules regardless of block order in this stylesheet. */
.es-fgrid__card.es-fgrid__card--glow::before { content: none; }

.es-fgrid__card.es-fgrid__card--glow h3 {
  transition: color var(--duration-normal) var(--ease-out);
}

.es-fgrid__card.es-fgrid__card--glow .es-fgrid__icon {
  transition: background-color var(--duration-normal) var(--ease-out),
              border-color var(--duration-normal) var(--ease-out),
              transform var(--duration-normal) var(--ease-out);
}

/* 17 Sep 2026, owner's reference ("Quality" card): the card keeps its place
   on hover (no lift) and takes the brand edge; the icon disc fills with the
   accent tint and grows slightly, without changing its ring colour. */
.es-fgrid__card.es-fgrid__card--glow:hover {
  border-color: var(--brand-200);
}

.es-fgrid__card.es-fgrid__card--glow:hover .es-fgrid__icon {
  background: var(--accent-subtle);
  /* No ring on the icon on hover (owner, 17 Sep 2026): the tinted disc alone. */
  border-color: transparent;
  transform: scale(1.06);
}

/* brand-500 rather than the darker brand-700, which read brown. Same
   orange the section headings use through .es-hl. */
.es-fgrid__card.es-fgrid__card--glow:hover h3 { color: var(--brand-500); }

/* ── Pill eyebrow ──────────────────────────────────────────
   The chip that used to be defined here, as `.es-fgrid__eyebrow`,
   is gone. It is the site-wide eyebrow now, so it lives on
   `.es-eyebrow` in utilities.css and this section renders that
   class like every other section does. Two definitions of one
   chip was how they would have drifted apart.

   The leading dot went earlier, on the owner's instruction, and
   with it the mirrored hairline that balanced it. */

/* ── Split head ────────────────────────────────────────────
   Eyebrow and title on the left, the supporting paragraph on
   the right, both left-aligned. The base .es-section-head caps
   itself at 780px so a single column stays readable; a head
   that spans two columns has to give that up, so the cap is
   lifted here and the reading width moved onto the paragraph
   itself, where it still applies.

   Bottom-aligned rather than centred: the paragraph is shorter
   than the title in every realistic case, and sitting it on the
   title's last line reads as one band instead of two blocks
   floating at different heights. */
/* Doubled with .es-section-head so the max-width reset beats the global
   head's own 780px cap on specificity rather than on load order. */
.es-section-head.es-fgrid__head--split {
  max-width: none;
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--gap-fluid-sm);
  align-items: end;
}

/* The lede's 20px top margin from the global head is spacing
   between stacked blocks. In a two-column grid the gap already
   does that job, so it would only push the paragraph out of
   alignment with the title. */
.es-section-head.es-fgrid__head--split .es-lede {
  margin: 0;
  max-width: 46ch;
}

@media (min-width: 992px) {
  .es-section-head.es-fgrid__head--split {
    grid-template-columns: minmax(0, 1.06fr) minmax(0, 0.94fr);
    gap: var(--gap-fluid-xl);
  }
}

/* ── Wide head, opt-in via `head: wide` ────────────────────
   One column like the default stacked head, but without the
   global head's 780px cap, so a long two-line title sets across
   the container instead of wrapping to four lines.

   The cap does not just disappear: it moves onto the paragraph,
   where it is actually doing its job. A title is scanned and can
   run long; a paragraph is read, and a 1300px line of 15px copy
   is unreadable no matter how much room there is.

   This is the third head arrangement, and the one to reach for
   when the design puts the lede under the title rather than
   beside it. `split` is the two-column version. */
.es-section-head.es-fgrid__head--wide { max-width: none; }

.es-section-head.es-fgrid__head--wide .es-lede { max-width: 58ch; }

/* The reading cap above is a box, not just a text width. On a
   LEFT head that box starts at the head's left edge, which is
   right. On a CENTRED head the head itself is `max-width: none`,
   so its own auto margins do nothing, and the capped lede stayed
   pinned to the left edge while the title centred above it. The
   paragraph read as centred text sitting off to one side. Centre
   the box too, and only when the head is actually centred. */
.es-section-head.es-fgrid__head--wide.text-center .es-lede { margin-inline: auto; }

/* Short brand rule closing the head, opt-in via `head_rule`. */
.es-fgrid__head--rule::after {
  content: "";
  display: block;
  width: 46px;
  height: 2px;
  margin: var(--gap-fluid-sm) auto 0;
  border-radius: 1px;
  background: var(--brand-500);
}

/* ── Section decoration ────────────────────────────────────
   Concentric arcs top right, a large outline circle on the
   left and a dot field on the right, all clipped by the
   section so none of it can push the page sideways. */
.es-fgrid--deco { position: relative; overflow: hidden; }
.es-fgrid--deco > .es-container { position: relative; z-index: 1; }

.es-fgrid__bg {
  position: absolute;
  inset: 0;
  z-index: 0;
  pointer-events: none;
}

.es-fgrid__bg::before {
  content: "";
  position: absolute;
  top: -170px;
  right: -170px;
  width: 440px;
  height: 440px;
  background-image: repeating-radial-gradient(circle at 100% 0%, transparent 0 46px, rgba(232, 93, 32, 0.16) 46px 47px);
  -webkit-mask-image: radial-gradient(circle at 100% 0%, #000, transparent 74%);
  mask-image: radial-gradient(circle at 100% 0%, #000, transparent 74%);
}

.es-fgrid__bg::after {
  content: "";
  position: absolute;
  left: -200px;
  top: 30%;
  width: 360px;
  height: 360px;
  border: 1px solid rgba(232, 93, 32, 0.18);
  border-radius: 50%;
}

.es-fgrid__dots {
  position: absolute;
  top: 26%;
  right: 2%;
  width: 118px;
  height: 130px;
  background-image: radial-gradient(circle at center, var(--brand-300) 1.2px, transparent 1.4px);
  background-size: 22px 22px;
  opacity: 0.75;
}

@media (max-width: 767px) {
  .es-fgrid__bg,
  .es-fgrid__dots { display: none; }
}

/* ── Card ──────────────────────────────────────────────────
   Rests on a hairline border, lifts on hover with the same
   translate/shadow/border-tint language as the homepage cards. */
.es-fgrid__card {
  position: relative;
  display: flex;
  flex-direction: column;
  padding: var(--space-6);
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-lg);
  background: var(--bg-surface);
  box-shadow: var(--shadow-xs);
  overflow: hidden;
  transition: transform var(--duration-normal) var(--ease-out),
              box-shadow var(--duration-normal) var(--ease-out),
              border-color var(--duration-normal) var(--ease-out);
}

.es-fgrid__card--lg { padding: var(--space-7); }

/* ── Hover: ambient warm-up ────────────────────────────────
   Replaces the old top rail, which drew a hard 3px bar across
   the card edge and fought the hairline border for attention.
   Instead a soft brand bloom fades in from the top-right and
   bottom-left corners, so the whole card warms rather than
   growing an edge. The card is `overflow: hidden`, so the wash
   is clipped to its radius. */
.es-fgrid__card::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  opacity: 0;
  background:
    radial-gradient(115% 85% at 100% 0%, rgba(232, 93, 32, 0.13), transparent 62%),
    radial-gradient(80% 70% at 0% 100%, rgba(232, 93, 32, 0.07), transparent 66%);
  transition: opacity var(--duration-slow) var(--ease-out);
}

/* Content rides above the wash. */
.es-fgrid__card > * { position: relative; z-index: 1; }

.es-fgrid__card:hover {
  transform: translateY(-6px);
  border-color: var(--brand-200);
  /* Neutral depth plus a brand tint, so the lift reads as warm
     rather than as a plain grey drop shadow. */
}

.es-fgrid__card:hover::before { opacity: 1; }

/* Same brand-500 the headings use through .es-hl. */
.es-fgrid__card:hover h3 { color: var(--brand-500); }

/* ── Card head ─────────────────────────────────────────────
   Kicker with its rule underneath rather than trailing it, so
   the label reads as a heading for the card. The rule widens on
   card hover. */
.es-fgrid__label {
  display: block;
  margin: 0 0 var(--space-5);
  font-family: var(--font-label);
  font-size: var(--fs-eyebrow);
  font-weight: var(--font-medium);
  letter-spacing: 1.6px;
  text-transform: uppercase;
  color: var(--brand-600);
}

.es-fgrid__label::after {
  content: "";
  display: block;
  width: 28px;
  height: 2px;
  margin-top: var(--space-2);
  border-radius: 1px;
  background: var(--brand-500);
  transition: width var(--duration-normal) var(--ease-out);
}

.es-fgrid__card:hover .es-fgrid__label::after { width: 54px; }

.es-fgrid__icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 56px;
  height: 56px;
  margin-bottom: var(--space-5);
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-md);
  background: var(--accent-subtle);
  color: var(--brand-500);
  transition: border-color var(--duration-normal) var(--ease-out),
              transform var(--duration-normal) var(--ease-out);
}

.es-fgrid__icon img { width: 28px; height: 28px; object-fit: contain; }
.es-fgrid__icon svg { width: 28px; height: 28px; }

.es-fgrid__card:hover .es-fgrid__icon {
  border-color: var(--brand-300);
  transform: translateY(-2px);
}

.es-fgrid__card h3 {
  margin: 0 0 var(--space-3);
  color: var(--text-heading);
  font-size: var(--fs-card-title);
  font-weight: var(--font-extrabold);
  line-height: var(--lh-subhead);
  letter-spacing: var(--tracking-normal);
  transition: color var(--duration-normal) var(--ease-out);
}

.es-fgrid__card--lg h3 { font-size: var(--fs-title-sm); }

.es-fgrid__card > p {
  margin: 0;
  color: var(--text-body);
  font-size: var(--fs-body-sm);
  line-height: var(--lh-body);
}

.es-fgrid__card--lg > p { font-size: var(--fs-body); }

/* ── Card bullet list ──────────────────────────────────────
   Rows separated by hairlines rather than gaps, each marked by
   a single arrow in a brand chip rather than a per-row icon, so
   a long list stays quiet and the eye lands on the copy. The
   rule under the last row is dropped so the list does not close
   with a stray line. */
.es-fgrid__list {
  list-style: none;
  margin: var(--gap-fluid-sm) 0 0;
  padding: 0;
  border-top: 1px solid var(--border-subtle);
}

.es-fgrid__list li {
  --es-fg-tick: 34px;
  display: grid;
  grid-template-columns: var(--es-fg-tick) 1fr;
  gap: var(--space-4);
  /* The mark is taller than one line and the row runs to two, so it
     centres on the whole row rather than on the first line. */
  align-items: center;
  padding: var(--space-4) 0;
  border-bottom: 1px solid var(--border-subtle);
}

.es-fgrid__list li:last-child { border-bottom: 0; padding-bottom: 0; }

/* Filled square tile rather than the round brand chip the rest of the
   page uses for ticks: these rows are statements of intent, not a
   completed checklist, and the square reads as a marker instead of a
   confirmation. */
.es-fgrid__tick {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: var(--es-fg-tick);
  height: var(--es-fg-tick);
  border-radius: var(--radius-sm);
  background: var(--gray-900);
  color: var(--text-inverse);
  transition: background-color var(--duration-normal) var(--ease-out),
              transform var(--duration-normal) var(--ease-out);
}

.es-fgrid__tick svg { width: 16px; height: 16px; }

/* Two lines that finish one sentence: the opening clause carries the
   weight, the continuation stays plain. Split rather than bolded
   inline so the row still scans as one line of copy at a glance. */
.es-fgrid__row {
  display: block;
  min-width: 0;
  font-size: var(--fs-body-sm);
  line-height: var(--lh-subhead);
}

.es-fgrid__lead {
  display: block;
  color: var(--text-heading);
  font-weight: var(--font-bold);
}

/* gray-600 rather than the lighter --text-muted: muted lands at
   3.8:1 on the card surface, which misses AA at this size. */
.es-fgrid__note {
  display: block;
  color: var(--gray-600);
}

/* The row under the pointer takes the brand mark and steps right.
   The text colour is deliberately left alone: these rows are not
   links, and re-inking them on hover suggests an affordance that
   is not there. */
.es-fgrid__list li:hover .es-fgrid__tick {
  background: var(--brand-500);
  transform: translateX(3px);
}

/* ── Card index, opt-in via `numbered` ─────────────────────
   Sits in the corner opposite the mark, so the card opens with
   the icon on the left and its place in the list on the right.
   Absolutely positioned rather than put in a flex row with the
   icon: the corner is empty in every card either way, and a
   wrapper would change the DOM for callers that never asked
   for a number.

   aria-hidden in the markup. The order is already carried by
   the document, and read aloud it turns every card heading
   into "zero one, Shopify Web Development Services". */
/* brand-600, not the brand-500 the marks and headings use. This is 15px
   text on the card surface, where brand-500 measures 3.49:1 and misses AA;
   brand-600 measures 4.67:1 and passes. Same reason .es-fgrid__label above
   is brand-600. */
.es-fgrid__card .es-fgrid__num {
  position: absolute;
  top: var(--space-6);
  right: var(--space-6);
  z-index: 1;
  color: var(--brand-600);
  font-family: var(--font-label);
  font-size: var(--fs-body-sm);
  font-weight: var(--font-semibold);
  letter-spacing: 1.2px;
  line-height: 1;
}

.es-fgrid__card--lg .es-fgrid__num {
  top: var(--space-7);
  right: var(--space-7);
}

/* ── Watermark, opt-in via `watermark` ─────────────────────
   An oversized, very faint copy of the card's own mark in the
   corner the index used to sit in. It reads as texture rather
   than as a second icon, which is the whole point: the card
   already states what it is, twice would be noise.

   Sits at z-index 0 with the hover wash, under the copy layer,
   and the card's overflow: hidden crops it to the radius so it
   bleeds off the corner instead of floating inside it.

   7% is deliberately below the threshold where it could affect
   the contrast of anything above it: the card's own copy stays
   on --bg-surface for measurement purposes, and by eye there is
   nothing to read through. Raising it much past 10% starts to
   show behind the heading. */
/* Inset from the top by exactly the same amount as from the right, so the
   mark sits in a square corner margin instead of being cropped by the card
   edge. That inset is the card's own padding, which also lines the
   watermark's top up with the top of the icon tile opposite it.

   Sitting fully inside the card puts a ceiling on its size: the heading
   starts one icon plus one gap below the padding, so the mark has to finish
   before that. Per density that is 80px of room on the default and large
   cards and 68px on the compact one, and the sizes below are set just under
   each. Bigger than that is what forced the old version to hang off the top
   edge in the first place. */
.es-fgrid__card .es-fgrid__wm {
  position: absolute;
  top: var(--space-6);
  right: var(--space-6);
  z-index: 0;
  color: var(--brand-500);
  opacity: 0.07;
  pointer-events: none;
  transition: opacity var(--duration-normal) var(--ease-out),
              transform var(--duration-normal) var(--ease-out);
}

.es-fgrid__card .es-fgrid__wm svg { width: 76px; height: 76px; }

/* --lg pads at space-7, so its corner inset follows the padding rather than
   staying at the default's space-6 and reading as a different alignment. */
.es-fgrid__card--lg .es-fgrid__wm {
  top: var(--space-7);
  right: var(--space-7);
}

/* These marks are line drawings on a 24-unit viewBox with a 1.6 stroke.
   Blown up to watermark size that stroke scales with everything else and
   lands around 6px, which stops reading as a drawn line and starts reading
   as a filled blob, quite unlike the same icon at 23px in the tile beside
   it. non-scaling-stroke holds the stroke at its authored width in screen
   pixels however far the shape is scaled, so the watermark is the same line
   weight as the small icon and simply larger. */
/* 3px rather than the authored 1.6, so the mark still reads as a drawn line
   at watermark scale instead of thinning out to a hairline. At 7% opacity a
   2.2px line was there on the spec sheet and gone on a real screen. This
   also levels the set: a few of these icons are authored at 1.7 and would
   otherwise sit slightly heavier than the rest. */
.es-fgrid__card .es-fgrid__wm svg * {
  vector-effect: non-scaling-stroke;
  stroke-width: 3px;
}

/* Warms very slightly with the rest of the card rather than
   staying inert while everything around it responds. */
.es-fgrid__card:hover .es-fgrid__wm {
  opacity: 0.11;
  transform: translateY(-2px);
}

.es-fgrid__card--compact .es-fgrid__wm {
  top: var(--space-5);
  right: var(--space-5);
}

/* 64px: the compact card's heading sits 92px down (24 padding, 52 icon, 16
   gap) and the mark starts at 24, so this clears the copy by 4px. */
.es-fgrid__card--compact .es-fgrid__wm svg { width: 64px; height: 64px; }

/* ── Compact density, opt-in via `density` ─────────────────
   Same card, less air. Scoped to its own class rather than
   tightened on --md, because the About page's second grid is
   --md too and did not ask to shrink. */
.es-fgrid__grid--compact { gap: var(--space-5); }

/* ── Aside layout: copy column beside the card wall ──────────
   Below the split breakpoint this is a plain block flow, so the head sits
   above the grid exactly as the stacked layout does and no rule here has
   to undo anything. Only the two-column arrangement is inside the query. */
.es-fgrid__head--aside { margin-bottom: var(--gap-fluid-md); }

/* The head caps itself at a reading width globally. In a column that is
   already half the section that cap fires twice and leaves the paragraph
   narrower than the column it lives in. Doubled selector to beat the
   global .es-section-head max-width, the same trick the split head uses. */
.es-section-head.es-fgrid__head--aside {
  max-width: none;
  text-align: left;
}

.es-section-head.es-fgrid__head--aside .es-lede { max-width: 46ch; }

/* Left, with the heading and the paragraph above it. The base rule centres
   the button, which is right under a centred head band and wrong beside a
   left-aligned column of copy.

   Doubled selector on purpose. `.es-fgrid__cta` is declared further down
   this sheet, so at equal specificity it wins on source order and the
   button stays centred. Two classes settle it wherever either rule sits. */
.es-fgrid__cta.es-fgrid__cta--aside {
  justify-content: flex-start;
  margin-top: var(--gap-fluid-sm);
}

@media (min-width: 992px) {
  .es-fgrid__aside {
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(0, 1.15fr);
    gap: var(--gap-fluid-xl);

    /* `start`, not `center`, and it is what makes the sticky copy column
       below work. A centred grid item is sized and placed against the
       middle of its area with no room to travel, so `position: sticky` on
       it has nothing to stick through. Start-aligned, the item sits at the
       top of a grid area as tall as the card wall beside it, which is the
       distance the copy is then free to ride down. */
    align-items: start;
  }

  /* The copy column holds while the cards scroll past it. The offset is the
     shared --sticky-offset the site already uses to clear the fixed header,
     so the heading never slides under the nav. Desktop only: on a stacked
     layout the copy is above the cards, so there is nothing to hold beside
     and sticking it would pin a block to the top of the viewport for no
     reason. */
  .es-fgrid__head--aside {
    position: sticky;
    top: var(--sticky-offset);
  }

  /* The head is a column now, not a band above one, so its bottom margin
     would only push it out of step with the cards beside it. */
  .es-fgrid__head--aside { margin-bottom: 0; }

  /* minmax(0, …) on both tracks above is what stops a long unbroken word
     in a card from widening the grid past its share; without it the cards
     column wins the fight and the copy column collapses. */
  .es-fgrid__aside > .es-fgrid__grid { min-width: 0; }
}

.es-fgrid__card.es-fgrid__card--compact { padding: var(--space-5); }

.es-fgrid__card--compact.es-fgrid__card--roundicon .es-fgrid__icon {
  width: 52px;
  height: 52px;
  margin-bottom: var(--space-4);
}

.es-fgrid__card--compact.es-fgrid__card--roundicon .es-fgrid__icon svg {
  width: 23px;
  height: 23px;
}

.es-fgrid__card--compact h3 { margin-bottom: var(--space-2); }

/* The arrow keeps `margin-top: auto`, so it stays pinned to the
   bottom edge and the row's arrows still line up. Only the space
   it reserves above itself shrinks. */
.es-fgrid__card--compact .es-fgrid__go { padding-top: var(--space-4); }

.es-fgrid__card--compact .es-fgrid__num {
  top: var(--space-5);
  right: var(--space-5);
}

/* ── Round mark, opt-in via `icon_shape` ───────────────────
   Same tile, dropped edge and a full radius. Larger than the
   square because a circle reads smaller than a rounded square
   of equal width, and 64px is the size the same treatment
   already uses in section-service-tabs. */
.es-fgrid__card--roundicon .es-fgrid__icon {
  width: 64px;
  height: 64px;
  border-color: transparent;
  border-radius: var(--radius-full);
}

/* ── Large mark, opt-in via `icon_size` ────────────────────
   The same disc at the size a card built around its mark wants,
   rather than the size a card that merely has one wants. Fluid,
   because it is set against the card's own width: at 3-up on a
   1320px container the card is roughly 416px and the disc reads
   as a quarter of it, which is the proportion the design draws.

   Its own modifier rather than a bigger --roundicon, because the
   About page's pillars and this page's Section 6 both run the
   64px disc and did not ask to grow. */
.es-fgrid__card--iconlg .es-fgrid__icon {
  width: clamp(84px, 7vw, 104px);
  height: clamp(84px, 7vw, 104px);
  margin-bottom: var(--gap-fluid-sm);
}

/* The artwork scales with the disc rather than sitting in the
   middle of it at 28px, which at 104px would read as a speck in
   a tinted circle. Same proportion the 64px disc holds. */
.es-fgrid__card--iconlg .es-fgrid__icon img,
.es-fgrid__card--iconlg .es-fgrid__icon svg {
  width: clamp(40px, 3.4vw, 50px);
  height: clamp(40px, 3.4vw, 50px);
}

/* ── Card title rule, opt-in via `title_rule` ──────────────
   Short brand rule between a card's heading and its copy, the
   same 28px-to-54px sweep `.es-fgrid__label` draws above and the
   same one the section head draws through `head_rule`, so the
   three rules on a page are one idiom at three scales.

   Drawn as a pseudo-element on the heading rather than as an
   element of its own: it is pure decoration, and a real <span>
   would put an empty node in the accessibility tree inside a
   heading, where a screen reader announces the heading's whole
   subtree. */
.es-fgrid__card--titlerule h3 { margin-bottom: var(--space-4); }

.es-fgrid__card--titlerule h3::after {
  content: "";
  display: block;
  width: 28px;
  height: 3px;
  margin-top: var(--space-4);
  border-radius: 2px;
  background: var(--brand-500);
  transition: width var(--duration-normal) var(--ease-out);
}

.es-fgrid__card--titlerule:hover h3::after { width: 54px; }

/* The brand-filled card inverts every other rule on the card, so
   this one goes with them or it vanishes into the orange. */
.es-fgrid__card--brand.es-fgrid__card--titlerule h3::after { background: var(--text-inverse); }

.es-fgrid__card--roundicon:hover .es-fgrid__icon { border-color: transparent; }

/* ── Card link, opt-in per item ────────────────────────────
   The arrow is the only real link, and the card is its hit
   area. `margin-top: auto` against the card's column flex
   pins it to the bottom edge, so the arrows line up across a
   row no matter how long each description runs. */
/* brand-600 to sit level with the index above rather than a shade brighter
   than it. The mark is non-text content, so it only owes 3:1 and brand-500
   would have cleared that, but two different oranges in opposite corners of
   the same card is the kind of drift the uniformity rule exists to stop. */
.es-fgrid__go {
  display: inline-flex;
  align-items: center;
  align-self: flex-start;
  margin-top: auto;
  padding-top: var(--gap-fluid-sm);
  color: var(--brand-600);
  transition: transform var(--duration-normal) var(--ease-out);
}

.es-fgrid__card:hover .es-fgrid__go { transform: translateX(4px); }

/* Uniform footer, 17 Sep 2026. An unlinked card in a wall that has links
   draws the same arrow in the same colour so all cards share one footer.
   It stays still on hover and the card keeps its default cursor, so it
   never promises a click the card cannot deliver. */
.es-fgrid__card:hover .es-fgrid__go--static { transform: none; }

/* The card element IS the anchor when the item carries a link, so it only
   needs the link resets. There is no stretched pseudo-element any more: an
   overlay only works while it keeps winning the stacking contest against
   everything the card ever grows, and when it loses, the card is dead
   except for the arrow. An anchor wrapping the content cannot fail that
   way, and it is what the keyboard already expected to focus. */
.es-fgrid__card--link {
  cursor: pointer;
  text-decoration: none;
  color: inherit;
}

/* The card clips to its radius, so the ring goes on the card itself with a
   positive offset rather than on anything inside it. */
.es-fgrid__card--link:focus-visible {
  outline: 2px solid var(--brand-500);
  outline-offset: 3px;
}

/* Centred CTA under the wall, same rhythm as the homepage. */
/* ── Brand card ────────────────────────────────────────────
   Solid brand panel for the card carrying the section's primary
   statement, so a pair reads as claim and supporting claim
   rather than two equal boxes.

   The fill is --brand-600, NOT the --brand-500 the buttons use.
   White on brand-500 measures 3.49:1, which clears AA only for
   large text and fails it for the body copy and the row text.
   brand-600 measures 4.67:1 and passes at every size in the
   card. If this ever moves back to brand-500, the copy has to
   go dark or it is no longer accessible.

   For the same reason nothing inside is a faded white: at 15px
   even white at 92% opacity drops to 4.19:1 here. The hierarchy
   is carried by weight and size instead, and every text layer
   stays at full --text-inverse.

   Doubled class throughout so these beat the base card's wash,
   hover tint and heading colour regardless of block order. */
.es-fgrid__card.es-fgrid__card--brand {
  border-color: var(--brand-600);
  background: var(--brand-600);
  box-shadow: var(--shadow-brand);
}

.es-fgrid__card--brand h3,
.es-fgrid__card--brand > p,
.es-fgrid__card--brand .es-fgrid__label,
.es-fgrid__card--brand .es-fgrid__lead,
.es-fgrid__card--brand .es-fgrid__note { color: var(--text-inverse); }

/* Regular weight against the lead's bold is the whole distinction
   between the two lines on this card, since tinting is not available. */
.es-fgrid__card--brand .es-fgrid__note { font-weight: var(--font-regular); }

/* .es-hl paints brand-500, which is invisible on a brand fill. The accent
   falls back to the italic alone here, so a highlighted phrase in a brand
   card's heading still reads as emphasis instead of disappearing. */
.es-fgrid__card--brand .es-hl { color: var(--text-inverse); }

.es-fgrid__card--brand .es-fgrid__label::after { background: var(--text-inverse); }

/* brand-500 on the brand fill is the same problem .es-hl has above: the
   index and the arrow would all but vanish. Both go to the inverse ink. */
.es-fgrid__card--brand .es-fgrid__num,
.es-fgrid__card--brand .es-fgrid__go { color: var(--text-inverse); }

/* The card leads with its kicker, so no mark is set by default. This
   keeps the tile correct on the saturated fill if an editor turns one
   back on, instead of dropping a near-white square onto the orange. */
.es-fgrid__card--brand .es-fgrid__icon {
  border-color: rgba(255, 255, 255, 0.30);
  background: var(--brand-800);
  color: var(--text-inverse);
}

.es-fgrid__card.es-fgrid__card--brand:hover .es-fgrid__icon {
  border-color: rgba(255, 255, 255, 0.55);
  background: var(--brand-800);
}

/* Hairlines are decoration, not text, so a translucent white is
   free to sit below the contrast floor here. */
.es-fgrid__card--brand .es-fgrid__list,
.es-fgrid__card--brand .es-fgrid__list li { border-color: rgba(255, 255, 255, 0.26); }

.es-fgrid__card--brand .es-fgrid__tick { background: var(--brand-800); }
.es-fgrid__card--brand .es-fgrid__list li:hover .es-fgrid__tick { background: var(--gray-900); }

/* The corner wash and the heading re-ink are both built for a light
   surface and do nothing legible on a saturated fill. */
.es-fgrid__card.es-fgrid__card--brand::before { content: none; }
.es-fgrid__card.es-fgrid__card--brand:hover h3 { color: var(--text-inverse); }

/* Keeps the lift it inherits from the hover variant, but deepens its own
   shadow instead of taking the light card's brand-tinted border. */
.es-fgrid__card.es-fgrid__card--brand:hover {
  border-color: var(--brand-600);
}

/* Diagonal rule field in the bottom-right corner, faded toward the
   copy so it never sits behind text. A repeating gradient rather
   than an asset: one declaration, scales to any card height, and
   costs no request. The card clips it to its own radius. */
.es-fgrid__card--brand::after {
  content: "";
  position: absolute;
  right: 0;
  bottom: 0;
  z-index: 0;
  width: 62%;
  height: 54%;
  pointer-events: none;
  background-image: repeating-linear-gradient(
    135deg,
    rgba(255, 255, 255, 0.17) 0 2px,
    transparent 2px 15px
  );
  -webkit-mask-image: radial-gradient(circle at 100% 100%, #000, transparent 72%);
  mask-image: radial-gradient(circle at 100% 100%, #000, transparent 72%);
}

.es-fgrid__cta {
  display: flex;
  justify-content: center;
  margin-top: var(--gap-fluid-lg);
}

@media (prefers-reduced-motion: reduce) {
  .es-fgrid__card,
  .es-fgrid__card::before,
  .es-fgrid__card h3,
  .es-fgrid__label::after,
  .es-fgrid__tick,
  .es-fgrid__go,
  .es-fgrid__icon { transition: none; }
  .es-fgrid__card:hover,
  .es-fgrid__card.es-fgrid__card--glow:hover { transform: none; }
  .es-fgrid__card:hover .es-fgrid__icon,
  .es-fgrid__card.es-fgrid__card--glow:hover .es-fgrid__icon { transform: none; }
  .es-fgrid__list li:hover .es-fgrid__tick { transform: none; }
  .es-fgrid__card:hover .es-fgrid__go { transform: none; }
}

/* ══════════════════════════════════════════════════════════
   LIGHT BRAND CARD, owner, 17 Sep 2026
   The Mission card moves from the solid orange panel to a light orange
   one: a soft brand-50 to brand-100 wash with a brand-200 edge, dark
   heading and body copy, orange accents. Overrides every inverse rule
   above, so the card reads like the light Vision card beside it with a
   warm tint.
   ══════════════════════════════════════════════════════════ */
.es-fgrid__card.es-fgrid__card--brand,
.es-fgrid__card.es-fgrid__card--brand:hover {
  border-color: var(--brand-200);
  background: linear-gradient(160deg, var(--brand-50) 0%, var(--brand-100) 100%);
  box-shadow: none;
}

.es-fgrid__card--brand h3,
.es-fgrid__card.es-fgrid__card--brand:hover h3,
.es-fgrid__card--brand .es-fgrid__lead { color: var(--text-heading); }

.es-fgrid__card--brand > p,
.es-fgrid__card--brand .es-fgrid__note { color: var(--gray-700); }

.es-fgrid__card--brand .es-fgrid__label { color: var(--brand-600); }

.es-fgrid__card--brand .es-fgrid__label::after,
.es-fgrid__card--brand.es-fgrid__card--titlerule h3::after { background: var(--brand-500); }

.es-fgrid__card--brand .es-hl,
.es-fgrid__card--brand .es-fgrid__num,
.es-fgrid__card--brand .es-fgrid__go { color: var(--brand-600); }

.es-fgrid__card--brand .es-fgrid__list,
.es-fgrid__card--brand .es-fgrid__list li { border-color: var(--brand-200); }

.es-fgrid__card--brand .es-fgrid__tick { background: var(--brand-500); color: var(--text-inverse); }
.es-fgrid__card--brand .es-fgrid__list li:hover .es-fgrid__tick { background: var(--brand-600); }

.es-fgrid__card--brand .es-fgrid__icon,
.es-fgrid__card.es-fgrid__card--brand:hover .es-fgrid__icon {
  border-color: var(--brand-200);
  background: var(--bg-surface);
  color: var(--brand-500);
}

.es-fgrid__card--brand::after {
  background-image: repeating-linear-gradient(
    135deg,
    rgba(232, 93, 31, 0.10) 0 2px,
    transparent 2px 15px
  );
}

/* Stronger light orange gradient (owner, 17 Sep 2026): white-warm at the top
   left deepening to a clear peach at the bottom right. */
.es-fgrid__card.es-fgrid__card--brand,
.es-fgrid__card.es-fgrid__card--brand:hover {
  border-color: var(--brand-200);
  background:
    radial-gradient(120% 90% at 100% 100%, rgba(255, 157, 107, 0.38) 0%, rgba(255, 157, 107, 0) 60%),
    linear-gradient(150deg, var(--brand-50) 0%, var(--brand-100) 55%, var(--brand-200) 100%);
}
