/* ==========================================================================
   Bunn Design Co. — Services page (page-specific system)

   Scoped to services.html only — not linked from any other page. Sits on top
   of assets/site.css exactly as about.css does, reusing its tokens, type
   scale, spacing scale, buttons, nav and footer as-is.

   This file deliberately duplicates (rather than shares) the small set of
   page-specific mechanisms about.css/about.js introduced — the masked
   heading reveal, the fade/rise/blur .about-reveal system, the film-grain
   layer, the green cursor and the muted-green motion tokens — under the
   exact same class names and values. about.html can't take a new shared
   <link>/<script> without being modified, so a literal copy under the same
   names is how this page reuses that system rather than inventing a
   slightly different one. Anything genuinely new to this page (hero, the
   service marquee, the category nav, the service cards) gets its own
   svc-* class instead, same discipline about.css used for its own new
   sections.
   ========================================================================== */

:root {
  --about-ease:      cubic-bezier(.2, .7, .2, 1);
  --about-ease-out:   cubic-bezier(.16, 1, .3, 1);
  --about-green-04:  rgba(75, 93, 52, .045);
  --about-green-08:  rgba(75, 93, 52, .09);
  --about-green-16:  rgba(75, 93, 52, .16);
  --about-green-35:  rgba(75, 93, 52, .35);
  --about-green-55:  rgba(75, 93, 52, .55);

  --about-t-hero:    clamp(2.75rem, 1.7rem + 5vw, 6.1rem);
  --about-t-heading: clamp(2.15rem, 1.55rem + 2.4vw, 3.55rem);

  --about-block-cream: #FAF7F0;
  --about-block-beige: #D6C7AF;
  --about-block-brown: #846A4E;
  --about-block-dark:  #2E2720;
}

/* ---------- page-wide texture: one fixed grain layer (identical to about.css) ---------- */
.about-grain {
  position: fixed; inset: 0; z-index: 1; pointer-events: none;
  opacity: .05; mix-blend-mode: multiply;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='180' height='180'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='2' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
}

/* ---------- custom cursor (identical to about.css) ---------- */
.about-cursor {
  position: fixed; left: 0; top: 0; z-index: 300;
  width: 7px; height: 7px; margin: -3.5px 0 0 -3.5px;
  border-radius: 50%;
  background: var(--blue);
  box-shadow: 0 0 10px 1px var(--about-green-55);
  opacity: 0; pointer-events: none;
  transition: opacity .25s ease, width .25s var(--about-ease), height .25s var(--about-ease),
              margin .25s var(--about-ease), border-radius .3s var(--about-ease),
              background .25s ease, box-shadow .25s ease;
  will-change: transform;
}
.about-cursor.is-ready { opacity: 1; }
.about-cursor.is-ring {
  width: 34px; height: 34px; margin: -17px 0 0 -17px;
  background: transparent; box-shadow: none;
  border: 1.5px solid var(--about-green-55);
}
.about-cursor.is-square {
  border-radius: 4px; transform: translate(-50%, -50%) rotate(45deg);
}
.about-cursor.is-ring.is-square { border-radius: 6px; }
body.about-cursor-active, body.about-cursor-active a, body.about-cursor-active button,
body.about-cursor-active .btn {
  cursor: none;
}

/* ---------- masked text reveal (identical to about.css) ---------- */
.about-mask {
  display: block; overflow: hidden;
  padding-bottom: .16em; margin-bottom: -.16em;
}
.about-mask__inner {
  display: block;
  transform: translateY(115%);
  filter: blur(6px);
  transition: transform .9s var(--about-ease), filter .7s ease;
  /* services.js writes --d per mask; the hero cascade below sets its base */
  transition-delay: var(--d, 0ms);
}
.about-mask.is-in .about-mask__inner { transform: translateY(0); filter: blur(0); }
@media (prefers-reduced-motion: reduce) {
  .about-mask__inner { transform: none; filter: none; transition: none; }
}
.no-js .about-mask__inner { transform: none; filter: none; }

/* ---------- generic fade+rise+sharpen reveal (identical to about.css) ---------- */
.about-reveal {
  opacity: 0; transform: translateY(18px) scale(.985); filter: blur(3px);
  transition: opacity .8s var(--about-ease), transform .8s var(--about-ease), filter .6s ease;
  transition-delay: var(--d, 0ms);
}
.about-reveal.is-in { opacity: 1; transform: none; filter: blur(0); }
@media (prefers-reduced-motion: reduce) {
  .about-reveal { opacity: 1; transform: none; filter: none; transition: none; }
}
.no-js .about-reveal { opacity: 1; transform: none; filter: none; }

.about-reveal.about-reveal--heading {
  transform: translateY(34px);
  transition-duration: .9s, .9s, .7s;
}
.about-reveal.about-reveal--fade {
  transform: translateY(6px) scale(1);
  filter: blur(1.5px);
  transition-duration: .6s, .6s, .5s;
}
.about-reveal.about-reveal--heading.is-in,
.about-reveal.about-reveal--fade.is-in {
  transform: none; filter: blur(0);
}
@media (prefers-reduced-motion: reduce) {
  .about-reveal.about-reveal--heading,
  .about-reveal.about-reveal--fade { transform: none; filter: none; }
}

/* the eyebrow's leading dash draws out from the left rather than arriving
   at full length (identical to about.css) — inherits the label's own --d */
.eyebrow.about-reveal::before {
  transform: scaleX(0); transform-origin: left;
  transition: transform .6s var(--about-ease);
  transition-delay: var(--d, 0ms);
}
.eyebrow.about-reveal.is-in::before { transform: scaleX(1); }
.no-js .eyebrow.about-reveal::before { transform: none; }

/* ---------- hairline that draws left-to-right on reveal (identical to about.css) ---------- */
.about-rule {
  height: 1px; background: var(--ink-14); border: 0; margin: 0;
  transform: scaleX(0); transform-origin: left;
  transition: transform .9s var(--about-ease); transition-delay: var(--d, 0ms);
}
.about-rule.is-in { transform: scaleX(1); }
.no-js .about-rule { transform: scaleX(1); }

/* magnetic attraction target (identical to about.css) */
[data-magnetic] { transition: transform .4s var(--about-ease-out); }

/* ==========================================================================
   1 — SERVICES HERO
   ========================================================================== */
.svc-hero {
  position: relative; isolation: isolate; overflow: hidden;
  padding-top: var(--s-6); padding-bottom: var(--s-6);
  background: var(--paper);
}
.svc-hero::before {
  content: ""; position: absolute; inset: -18% 0; z-index: -1;
  background: radial-gradient(120% 90% at 82% 15%, var(--about-green-08), transparent 60%);
  pointer-events: none;
  transform: translateY(var(--wash-y, 0px));
}
.svc-hero__eyebrow { margin-bottom: var(--s-3); }
.svc-hero__title {
  font-size: var(--about-t-hero); line-height: .98; letter-spacing: -.045em;
  max-width: 17ch;
  text-wrap: balance;
}
.svc-hero__title .about-mask__inner {
  font-family: var(--display); font-weight: 700; font-style: normal; letter-spacing: -.045em;
}
.svc-hero__title .serif { letter-spacing: -.01em; }
.svc-hero__lead { margin-top: var(--s-5); max-width: 46ch; text-wrap: pretty; }

/* ---------- hero entrance choreography (same idea as about.css) ----------
   Everything here is above the fold, so every observer fires in the same
   frame and, left alone, the label, headline and lead arrive as one slab.
   These three delays play them in reading order instead. Slightly tighter
   than the About page's cascade — this hero is three elements, not five,
   and the category nav sits right beneath it waiting to be used. */
.svc-hero__eyebrow.about-reveal { --d: 40ms; }
.svc-hero__title .about-mask__inner { --d: 190ms; }
.svc-hero__lead.about-reveal { --d: 620ms; }

/* The hero's surface is the shared mouse-reactive weave (hero-texture.css /
   hero-texture.js) — the same field the homepage, About and the case studies
   use. It replaced a hand-placed cluster of cube-language blocks that used to
   live here. Nothing else is needed in this file: .svc-hero already carries
   the position/isolation/overflow the canvas layers into, and
   data-hero-quiet on the section names the copy the weave thins out around. */

/* ==========================================================================
   2 — SERVICE MARQUEE
   Full-bleed banner: two identical concatenated tracks scroll as one unit
   so the loop is seamless, animating toward 0% (not away from it) so the
   words visibly travel left -> right, matching the site's calm, linear,
   never-competing motion register — the only place on the page that uses a
   continuous loop rather than a settle-once entrance.
   ========================================================================== */
.svc-marquee {
  position: relative; overflow: hidden;
  padding-block: var(--s-3);
  /* same paper as the hero and category nav either side of it — no banded
     "different section" read, it just sits in the page like a continuous
     strip of small print running past */
  background: var(--paper);
  border-block: 1px solid var(--ink-14);
  -webkit-mask-image: linear-gradient(to right, transparent 0, #000 min(10%, 110px), #000 calc(100% - min(10%, 110px)), transparent 100%);
  mask-image: linear-gradient(to right, transparent 0, #000 min(10%, 110px), #000 calc(100% - min(10%, 110px)), transparent 100%);
}
.svc-marquee__group {
  display: flex; width: max-content;
  animation: svcMarqueeFlow 52s linear infinite;
}
.svc-marquee__track {
  display: flex; align-items: center; flex: none;
  gap: clamp(1.5rem, 3vw, 2.4rem);
  padding-right: clamp(1.5rem, 3vw, 2.4rem);
}
/* sized and coloured like the site's small uppercase labels (.eyebrow) —
   a quiet strip of running text, not a second headline-scale banner. The
   dot is a separate flex item between each pair of words (a true
   separator), not a leading icon glued to one word like a bullet. */
.svc-marquee__item {
  display: inline-flex; align-items: center;
  font-family: var(--display); font-weight: 600;
  font-size: var(--t-xs);
  letter-spacing: .1em; text-transform: uppercase;
  color: var(--ink-55); white-space: nowrap;
}
.svc-marquee__mark {
  width: 5px; height: 5px; flex: none; border-radius: 50%;
  background: var(--blue);
}
@keyframes svcMarqueeFlow {
  from { transform: translateX(-50%); }
  to   { transform: translateX(0); }
}

/* ==========================================================================
   3 — CATEGORY NAV (not sticky — scrolls with the page like everything else)
   ========================================================================== */
.svc-cat-nav {
  background: var(--paper); border-block: 1px solid var(--ink-14);
}
.svc-cat-nav__inner {
  max-width: var(--maxw); margin-inline: auto; padding-inline: var(--gutter);
  padding-block: var(--s-3);
  display: flex; gap: var(--s-2); overflow-x: auto; scrollbar-width: none;
}
.svc-cat-nav__inner::-webkit-scrollbar { display: none; }
/* Real buttons in the same language as .btn elsewhere on the site — a fill
   that swaps on hover rather than just a border darkening, plus the same
   [data-magnetic] pointer-follow the CTA buttons use, so this row reads as
   pressable rather than as a strip of links. The blue hover fill is the
   site's "about to act" colour (see .btn:hover); the active category still
   gets the site's solid "selected" ink fill so the two states stay visually
   distinct from each other. */
.svc-cat-nav a {
  --cn-bg: var(--paper); --cn-fg: var(--ink-70); --cn-bd: var(--ink-14);
  flex: none; display: inline-flex; align-items: center; min-height: 44px;
  font-family: var(--display); font-weight: 600; font-size: var(--t-sm);
  padding: 0 var(--s-3);
  border-radius: 999px;
  border: 1px solid var(--cn-bd);
  background: var(--cn-bg);
  color: var(--cn-fg);
  transition: background .28s var(--about-ease), border-color .28s var(--about-ease),
    color .28s var(--about-ease), box-shadow .28s var(--about-ease);
}
.svc-cat-nav a:hover, .svc-cat-nav a:focus-visible {
  --cn-bg: var(--blue); --cn-bd: var(--blue); --cn-fg: #fff;
  box-shadow: 0 8px 18px var(--about-green-16, rgba(17,17,17,.1));
}
.svc-cat-nav a.is-active {
  --cn-bg: var(--ink); --cn-bd: var(--ink); --cn-fg: var(--paper);
}
.svc-cat-nav a.is-active:hover, .svc-cat-nav a.is-active:focus-visible {
  --cn-bg: var(--blue); --cn-bd: var(--blue);
}

/* ==========================================================================
   4 — SERVICE CATEGORIES
   ========================================================================== */
.svc-cat {
  padding-block: var(--s-7); border-bottom: 1px solid var(--ink-14);
  /* site.css already sets scroll-padding-top on <html> (nav-space + s-2) to
     clear the fixed nav for every anchor jump on the whole site — adding a
     second full nav-space reservation here stacked on top of that, so
     clicking a category link landed with roughly double the intended gap
     above the heading. Just a touch of extra breathing room beyond what
     the fixed nav already needs, not a second copy of the same offset. */
  scroll-margin-top: var(--s-3);
}
.svc-cat:last-of-type { border-bottom: 0; }
.svc-cat__label { margin-bottom: var(--s-2); }
.svc-cat__title {
  font-size: var(--about-t-heading); max-width: 22ch; text-wrap: balance;
}
.svc-cat__desc {
  margin-top: var(--s-4); max-width: 58ch; color: var(--ink-70);
  font-size: var(--t-lead); text-wrap: pretty;
}
.svc-cat__rule { margin-top: var(--s-5); margin-bottom: var(--s-5); }

.svc-chips { display: flex; flex-wrap: wrap; gap: .5rem 0; margin-bottom: var(--s-4); }
.svc-chips li {
  font-family: var(--display); font-weight: 600; font-size: var(--t-sm); color: var(--ink-55);
}
.svc-chips li + li::before { content: "\00b7"; margin-inline: .8rem; color: var(--ink-14); }

.svc-list { display: grid; gap: var(--s-3); }
.svc-item {
  position: relative; overflow: hidden;
  background: var(--paper-2); border: 1px solid var(--ink-14);
  transition: transform .4s var(--about-ease-out), border-color .3s ease, box-shadow .35s ease;
}
/* These rows are the page — every service on offer is one of them — so the
   hover is built as a small composed moment rather than a lift alone:
     - a green wash wipes in from the left edge (the same left-to-right
       travel the About page's process rows use when they activate),
     - the service name takes a short nudge in the same direction,
     - the +/- disc picks up the accent colour,
     - the border warms from grey to the green accent.
   All four resolve on the same curve, so they read as one gesture. The
   wash is a scaleX-ed pseudo-element rather than a background transition:
   an opacity fade on a full-width tint arrives everywhere at once and
   loses the direction, which is the part that ties it to the rest of the
   site's motion. */
.svc-item::before {
  content: ""; position: absolute; inset: 0; z-index: 0; pointer-events: none;
  /* weighted to the left edge and gone by ~78% — a flat tint across the
     whole row read as a muddy grey rather than as green arriving from a
     direction, which is the entire point of the wipe. First pass leaned on
     --about-green-16 at the leading edge, which read as too strong a colour
     hit for a plain list hover; --about-green-08 keeps the same falloff
     shape at roughly half the intensity. */
  background: linear-gradient(90deg, var(--about-green-08), var(--about-green-04) 46%, transparent 82%);
  transform: scaleX(0); transform-origin: left;
  transition: transform .5s var(--about-ease);
}
.svc-item:hover::before { transform: scaleX(1); }
.svc-item:hover,
.svc-item.about-reveal.is-in:hover {
  transform: translateY(-4px);
  border-color: var(--about-green-35);
  box-shadow: 0 14px 28px rgba(17, 17, 17, .08);
}
.svc-item > summary {
  position: relative; z-index: 1;
  list-style: none; cursor: pointer;
  display: grid; grid-template-columns: minmax(0, 1fr) auto;
  gap: var(--s-3) var(--s-4); align-items: center;
  padding: var(--s-4);
  min-height: 64px;
}
.svc-item > summary::-webkit-details-marker { display: none; }
.svc-item__name {
  font-family: var(--display); font-weight: 700; font-size: var(--t-h3); letter-spacing: -.03em;
  display: inline-block;
  transition: transform .38s var(--about-ease);
}
.svc-item:hover .svc-item__name { transform: translateX(6px); }
.svc-item__desc { color: var(--ink-70); font-size: var(--t-sm); margin-top: .35rem; max-width: 56ch; }
.svc-item__chev {
  width: 40px; height: 40px; flex: none; border: 1.5px solid var(--ink); border-radius: 999px;
  display: grid; place-items: center; transition: transform .3s ease, background .2s, color .2s, border-color .2s;
}
/* :not([open]) rather than source order — the open state's filled green disc
   has to outrank the hover treatment, and the two selectors are otherwise
   the same specificity. */
/* scale, not rotation: the glyph is a plus, so any quarter-turn is invisible
   and a 45deg turn would claim the row is already open. */
.svc-item:not([open]):hover .svc-item__chev {
  border-color: var(--blue); color: var(--blue-ink);
  transform: scale(1.08);
}
.svc-item[open] .svc-item__chev { transform: rotate(45deg); background: var(--blue); border-color: var(--blue); color: #fff; }
/* z-index keeps the opened panel above the hover wash pseudo-element */
.svc-item__panel { position: relative; z-index: 1; padding: 0 var(--s-4) var(--s-4); }

/* ---- the open/close motion ----
   The box itself grows and collapses via ::details-content, which browsers
   that support it can transition natively — including to and from `auto`,
   once interpolate-size opts in. That's the whole animation on modern
   engines: no JS, and it works for keyboard toggles and find-in-page
   expansion too, not just clicks. services.js feature-detects this exact
   pair and only runs its own height tween where it's missing, so the two
   paths can never both drive the same box. */
.svc-item { interpolate-size: allow-keywords; }
.svc-item::details-content {
  height: 0; overflow: hidden;
  transition: height .42s var(--about-ease), content-visibility .42s allow-discrete;
}
.svc-item[open]::details-content { height: auto; }

/* the content's own entrance once the box has room for it — fades and
   settles up, same blur-to-sharp language as .about-reveal, timed to
   resolve just as the box finishes expanding. */
.svc-item__panel-inner {
  border-top: 1px solid var(--ink-14); padding-top: var(--s-4);
  opacity: 0; transform: translateY(10px); filter: blur(3px);
  transition: opacity .45s var(--about-ease) .08s, transform .45s var(--about-ease) .08s, filter .35s ease .08s;
}
.svc-item[open] .svc-item__panel-inner { opacity: 1; transform: none; filter: blur(0); }
@media (prefers-reduced-motion: reduce) {
  .svc-item__panel-inner { transition: none; }
  .svc-item::details-content { transition: none; }
}
.svc-item__incl { display: grid; gap: .5rem; }
.svc-item__incl h3 {
  font-family: var(--display); font-size: var(--t-xs); font-weight: 600;
  letter-spacing: .14em; text-transform: uppercase; color: var(--ink-55);
}
/* the included points arrive one after another once the box has opened,
   rather than the whole list appearing as a slab the instant there's room
   for it — a short stagger is what makes the panel feel like it's being
   filled in rather than revealed. Delays are absolute (not a counter) so
   they stay in step with .svc-item__panel-inner's own .08s head start; the
   longest list on the page is six points, and a seventh would simply share
   the sixth's timing rather than break. */
.svc-item__incl li {
  position: relative; padding-left: 1.4rem; font-size: var(--t-sm); color: var(--ink-70);
  opacity: 0; transform: translateY(6px);
  transition: opacity .4s var(--about-ease), transform .4s var(--about-ease);
}
.svc-item[open] .svc-item__incl li { opacity: 1; transform: none; }
.svc-item[open] .svc-item__incl li:nth-child(1) { transition-delay: .16s; }
.svc-item[open] .svc-item__incl li:nth-child(2) { transition-delay: .22s; }
.svc-item[open] .svc-item__incl li:nth-child(3) { transition-delay: .28s; }
.svc-item[open] .svc-item__incl li:nth-child(4) { transition-delay: .34s; }
.svc-item[open] .svc-item__incl li:nth-child(n + 5) { transition-delay: .40s; }
.svc-item__incl li::before {
  content: ""; position: absolute; left: 0; top: .62em;
  width: 8px; height: 8px; background: var(--blue);
}
/* no-JS and reduced-motion both have to end with the points simply visible —
   the [open] attribute is still what gates them, this only removes the
   motion in between. */
@media (prefers-reduced-motion: reduce) {
  .svc-item__incl li { opacity: 1; transform: none; transition: none; }
}
.no-js .svc-item__incl li { opacity: 1; transform: none; }
@media (max-width: 700px) {
  .svc-item > summary { grid-template-columns: minmax(0, 1fr) auto; }
}

/* ==========================================================================
   5 — FINAL CALL TO ACTION (identical to about.css's .about-cta)
   ========================================================================== */
.about-cta {
  position: relative; isolation: isolate; overflow: hidden;
  min-height: 62vh; min-height: 62svh;
  display: flex; align-items: center;
  background: linear-gradient(180deg, var(--blue-dark) 0%, var(--night) 94%);
  color: var(--paper);
  padding-block: var(--s-6);
}
.about-cta__canvas { position: absolute; inset: 0; width: 100%; height: 100%; opacity: .5; }
.about-cta__inner { position: relative; z-index: 1; width: 100%; }
.about-cta__eyebrow { color: rgba(245,243,237,.85); }
.about-cta__eyebrow::before { background: rgba(245,243,237,.7); }
.about-cta__title {
  margin-top: var(--s-3);
  font-size: var(--about-t-heading);
  max-width: 16ch; color: #fff;
}
.about-cta__body { margin-top: var(--s-4); max-width: 46ch; color: rgba(245,243,237,.82); font-size: var(--t-lead); text-wrap: pretty; }
.about-cta__actions { margin-top: var(--s-5); }

@media (max-width: 900px) {
  .svc-hero__title { max-width: 14ch; }
}
@media (max-width: 560px) {
  .svc-cat-nav__inner { gap: var(--s-2); }
}
