/* Modelibrary — multi-page site.
   Light ground, navy ink, one action blue; a serif display face over a sans body.
   Pages cross-fade into each other; see "page transitions" at the foot of this file. */

:root{
  color-scheme:light;
  /* A neutral, muted scrollbar rather than the browser's stark white-on-light-scheme
     default, which reads as a stray white bar wherever it overlaps a dark band
     (the hero, page heads, the footer). scrollbar-color has no way to vary by what
     is behind it, so this is one compromise pair rather than a per-section fix. */
  scrollbar-color:var(--dim) var(--line-soft);
  scrollbar-width:thin;
  --paper:#ffffff;
  --paper-2:#f4f7fb;          /* cool tint: alternating bands, hover fills */
  --navy:#000f47;             /* ink */
  --navy-deep:#032051;        /* hero, page heads, footer */
  --ink:var(--navy);
  --muted:#4e6287;
  --dim:#5f7192;
  --line:#d9dfea;
  --line-soft:#eceff5;
  --accent:#0b4bff;           /* links, arrows, the one solid button */
  --accent-soft:#2f66ff;
  --pale:#ceecff;             /* headings on navy; the solution discs */
  --sky:#95caff;
  --on-navy:#e7eef3;          /* body text on navy */
  --hero-bg:var(--navy-deep);

  --display:Georgia,'Iowan Old Style','Palatino Linotype','Book Antiqua',serif;
  --text:'Segoe UI','Noto Sans','Helvetica Neue',Helvetica,Arial,sans-serif;

  --gut:clamp(16px,4vw,32px);
  --shell:1600px;
  --measure:70ch;
  --radius:6px;

  /* Motion. Two durations and two eases, used everywhere, so hover behaviour is
     consistent rather than per-component guesswork. The prefers-reduced-motion
     block below collapses every duration to .001ms, so nothing needs a second opt-out. */
  --dur:170ms;
  --dur-slow:300ms;
  --dur-hero:420ms;      /* the poster-to-canvas cross-fade */
  --dur-hero-in:600ms;   /* the whole stage easing up on first paint */
  --ease:cubic-bezier(.22,.61,.36,1);
  --ease-out:cubic-bezier(.16,1,.3,1);

  font-family:var(--text);
  color:var(--ink);
  background:var(--paper);
}

*{box-sizing:border-box}
html{-webkit-text-size-adjust:100%;scroll-behavior:smooth}
body{margin:0;font-size:16px;line-height:1.55;overflow-x:hidden}
img{max-width:100%}
a{color:inherit;text-decoration:none}
a:focus-visible,button:focus-visible,summary:focus-visible{outline:3px solid var(--accent);outline-offset:4px}
h1,h2,h3,h4{margin:0;font-weight:400}
p{margin:0}
ul,ol{margin:0;padding:0;list-style:none}
figure{margin:0}

.shell{max-width:var(--shell);width:100%;margin:0 auto;padding:0 var(--gut)}
.skip{position:absolute;left:30px;top:-100px;padding:12px;background:var(--paper);z-index:20}
.skip:focus{top:16px}
.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}

/* ---------- header ---------- */
/* Full-bleed background/border; .shell inside caps and centres the actual row so it
   doesn't stretch to the viewport edge on wide screens. */
.site-header{min-height:80px;position:sticky;top:0;z-index:12;background:var(--paper);border-bottom:1px solid var(--line)}
.site-header .shell{height:100%;min-height:80px;display:flex;align-items:center;justify-content:space-between;gap:24px}
.wordmark{font-family:var(--display);font-size:1.625rem;letter-spacing:-.3px;color:var(--navy);
  display:inline-flex;align-items:center;min-height:44px}
.brand-period{color:var(--accent)}
.site-nav{display:flex;align-items:center;gap:34px;font-size:.9375rem;font-weight:600}
.site-nav a{padding:12px 0;color:var(--navy);position:relative}
.site-nav a:hover{color:var(--accent)}
.site-nav a[aria-current]{color:var(--accent)}
.nav-toggle{display:none;font:inherit;font-weight:600;color:var(--navy);background:none;border:1px solid var(--line);
  padding:10px 16px;cursor:pointer;border-radius:var(--radius)}

/* ---------- hero ---------- */
/* The navy band bleeds edge to edge; .hero-inner (combined with .shell) caps the
   headline/copy/artwork at --shell width so they don't stretch on wide screens.
   hero-stage's inset values are unchanged pixel offsets from THIS box's padding
   edge, which used to be .hero's — moving them here keeps that geometry intact.
   isolation stays on .hero, NOT .hero-inner: the stage's screen blend cancels the
   canvas's opaque black against whatever is in its isolated group, and the navy
   background lives on .hero. Isolating .hero-inner instead leaves the blend with
   a transparent backdrop, and the black rectangle shows. */
.hero{position:relative;isolation:isolate;background:var(--hero-bg);color:var(--on-navy);overflow:hidden}
.hero-inner{position:relative;min-height:720px;
  display:flex;flex-direction:column;justify-content:space-between;padding:56px var(--gut)}
.hero h1{position:relative;z-index:2;align-self:flex-end;text-align:right;font-family:var(--display);
  font-size:clamp(2.5rem,5.4vw,5rem);line-height:1.05;letter-spacing:-.5px;color:var(--pale);
  max-width:100%;text-shadow:0 2px 18px #00000066}
.hero h1 span{display:block}
.hero-copy{position:relative;z-index:2;max-width:400px;margin-top:180px}
.hero-copy h2{font-family:var(--display);font-size:2rem;line-height:1.1;margin:0 0 18px;color:#fff}
.intro{font-size:1.0625rem;line-height:1.6;max-width:36ch;margin:0 0 28px;color:var(--on-navy)}
.hero-actions{display:flex;flex-wrap:wrap;gap:14px}

/* 3D mount point — see 3d-slot.md. Poster is the rendered state until a runtime is bound. */
.hero-stage{position:absolute;z-index:0;inset:155px -70px -55px 30%;pointer-events:none}
/* Stacked, not laid out in a row. Both are children of a flex container, so as
   in-flow items the poster took a ~970px slot of its own and shoved the canvas
   off the right edge of the hero. visibility:hidden after the cross-fade stops
   the poster painting but keeps its layout box, so the shove survived the fade.
   Taking both out of flow overlays them, which is what the cross-fade assumed. */
.hero-stage img,.hero-stage canvas{position:absolute;inset:0;
  display:block;width:100%;height:100%;object-fit:contain;
  opacity:1;mix-blend-mode:screen;transform:none}
.hero-stage:after{content:"";position:absolute;inset:0;
  pointer-events:none}
/* The whole stage eases up on first paint, as one unit, so the artwork arrives
   rather than appearing. CSS animation, not a JS class, so it still runs with
   JavaScript disabled — a JS-gated opacity:0 would leave the hero invisible.
   Only a `from` keyframe: the implicit `to` is whatever opacity the cascade gives
   the stage, which preserves the .75 and .9 values set at narrow breakpoints.
   The headline and copy are deliberately NOT faded — "no page-text animation". */
@keyframes hero-in{from{opacity:0}}
.hero-stage{animation:hero-in var(--dur-hero-in) var(--ease-out) backwards}

/* Cross-fade, not a cut. `data-reveal` is set one frame after bind so the opacity
   transition has a start value to animate from. Clearing it fades the poster back in. */
.hero-stage .hero-poster,.hero-stage canvas,.hero-stage:after{
  transition:opacity var(--dur-hero) var(--ease-out)}
/* Once faded, the poster leaves rendering entirely: at opacity 0 it still composites,
   and under the stage's screen blend that showed as a ghost behind the live artwork. */
.hero-stage .hero-poster{visibility:visible;
  transition:opacity var(--dur-hero) var(--ease-out),visibility 0s linear 0s}
.hero-stage[data-reveal="on"] .hero-poster{visibility:hidden;
  transition:opacity var(--dur-hero) var(--ease-out),
             visibility 0s linear var(--dur-hero)}

/* Mounted, holding its first frame, still invisible behind the poster. */
.hero-stage[data-runtime="bound"] canvas{opacity:0;filter:none;pointer-events:auto;
  cursor:grab;mix-blend-mode:normal}

/* Revealed. */
.hero-stage[data-reveal="on"] canvas{opacity:1}
.hero-stage[data-reveal="on"] .hero-poster{opacity:0}
.hero-stage[data-reveal="on"]{mix-blend-mode:screen}
.hero-stage[data-reveal="on"]:after{opacity:0}
.hero-stage.is-dragging canvas{cursor:grabbing}

/* .hero-live is set on <html> before first paint by the inline bootstrap, on exactly
   the clients heroSlot.eligible() will accept. There the poster is never shown at
   all. Phones, coarse pointers, reduced-motion, save-data and no-JS clients keep the
   poster and get no animation. fallback() removes the class, so a failed bind still
   shows it. The renderer clears to opaque black (alpha:false); the screen blend
   cancels that against the navy band, and is applied immediately rather than at
   data-reveal since there is no poster to cross-fade from. */
.hero-live .hero-stage .hero-poster{display:none}
.hero-live .hero-stage{mix-blend-mode:screen}
.hero-live .hero-stage:after{opacity:0}
/* Phones get the opaque streamline render rather than the alpha poster, and it depends on
   the screen blend to lose its black ground. The img's own mix-blend-mode is trapped inside
   the stage's stacking context (absolute, z-index 0), so the blend has to sit on the stage —
   which is what .hero-live and data-reveal already do for desktop. Same breakpoint as the
   <source> that selects the render. .hero's isolation keeps it against the navy band. */
@media(max-width:699px){.hero-stage{mix-blend-mode:screen}}
/* The morph and pause buttons stay in the DOM and in the tab order — 3d-slot.md
   requires a named control for each, and the artwork animates on load, so someone
   without a pointer must still be able to stop it. Hidden until keyboard focus
   reaches them, the same trick the skip link uses. */
.hero-controls{opacity:0;pointer-events:none;
  transition:opacity var(--dur) var(--ease);
  position:absolute;z-index:3;right:25px;bottom:27px;display:flex;align-items:center;
  gap:8px;color:var(--on-navy);font-size:.6875rem}
.hero-controls button{min-height:40px;padding:8px 12px;border:1px solid #ffffff55;
  background:#032051df;color:var(--on-navy);font:inherit;cursor:pointer;border-radius:var(--radius)}
.hero-controls button:hover,.hero-controls button[aria-pressed="true"]{color:#fff;
  border-color:var(--pale);background:var(--navy)}
.hero-controls:focus-within{opacity:1;pointer-events:auto}
@media print{.hero-controls{display:none}}

/* ---------- buttons ---------- */
.primary{display:inline-flex;align-items:center;gap:14px;background:var(--accent);color:#fff;
  padding:14px 22px;min-height:50px;font-size:.9375rem;font-weight:600;border-radius:var(--radius)}
.ghost{display:inline-flex;align-items:center;gap:12px;border:1px solid var(--navy);padding:13px 22px;
  min-height:50px;font-size:.9375rem;font-weight:600;color:var(--navy);border-radius:var(--radius)}
.ghost-light{border-color:var(--pale);color:var(--pale)}
.more,.learn{display:inline-flex;align-items:center;gap:10px;color:var(--accent);font-weight:600;font-size:.9375rem}
/* .more is a real link standing on its own; .learn is a label inside a card that is
   already one large target. Padding brings .more to a 44px hit area and the matching
   negative margin gives the padding back, so nothing around it moves. */
.more{padding:11px 0;margin:-11px 0}

/* ---------- home: explore our solutions ---------- */
.explore{padding:clamp(56px,7vw,110px) 0}
.explore-head{display:flex;justify-content:space-between;align-items:baseline;gap:24px;flex-wrap:wrap;
  margin-bottom:clamp(32px,4vw,56px)}
.explore-head h2{font-family:var(--display);font-size:clamp(1.875rem,3vw,2.5rem);color:var(--navy);line-height:1.15}
.solution-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:clamp(36px,4vw,60px) clamp(24px,3vw,40px)}
/* A hairline above each card, the same rule the bands open with, so the six read as
   bounded groups rather than as things that happen to be near each other. */
.solution-card{display:flex;flex-direction:column;gap:16px;position:relative;
  border-top:1px solid var(--line);padding-top:28px}
/* Serif, like every other heading on the site. These and the 404 cards were the only
   two sans headings, for no reason anyone could name. */
.solution-card h3{font-family:var(--display);font-size:1.5rem;line-height:1.2;color:var(--navy)}
.solution-card h3 a:after{content:"";position:absolute;inset:0}
.solution-card p{color:var(--muted);line-height:1.6}
.solution-card p:not(.learn){flex:1}

/* The solution mark: a hairline ring holding a geometric line glyph, one per service.
   Strokes are in user units and scale with the mark, so the same glyph reads at the
   140px home card and the 280px band without a second set of rules. */
.solution-mark{width:clamp(150px,15vw,210px);aspect-ratio:1;
  transition:transform var(--dur-slow) var(--ease-out)}
.solution-mark svg{display:block;width:100%;height:100%;overflow:visible}
.solution-mark .ring{fill:none;stroke:var(--line);stroke-width:1}
.solution-mark .ink,.solution-mark .ink-2{fill:none;stroke-linecap:round;stroke-linejoin:round}
.solution-mark .ink{stroke:var(--accent);stroke-width:1.2}
.solution-mark .ink-2{stroke:var(--sky);stroke-width:.9}
.solution-mark .dashed{stroke-dasharray:4 4}
.solution-mark .dot{fill:var(--sky)}
.solution-mark .node{fill:var(--accent)}
/* Hover draws a ring around the mark, the nav underline's gesture bent into a circle.
   pathLength normalises the length to 100 units, so one rule covers every rendered size.

   The dash grows from zero rather than a full dash being slid out of view by an offset.
   Both hide the sweep at rest on paper, but the offset version leaves the dash boundary
   sitting exactly on the path's start, and the renderer paints a hairline tick there at
   twelve o'clock on every mark. A zero-length dash cannot draw anything at all. */
.solution-mark .ring-sweep{fill:none;stroke:var(--accent);stroke-width:1.1;stroke-linecap:butt;
  stroke-dasharray:0 100;transform:rotate(-90deg);transform-origin:50% 50%;
  transition:stroke-dasharray var(--dur-slow) var(--ease-out)}
.solution-card:hover .ring-sweep,.solution-card:focus-within .ring-sweep{stroke-dasharray:100 100}
.solution-card:hover .solution-mark{transform:translateY(-4px)}
/* The numeral lost its circle, so it joins the card as the micro-label the rest of the
   site already uses. The card's own gap does the spacing. */
.solution-card .eyebrow{margin-bottom:0}
.solution-card:hover h3{color:var(--accent)}

/* ---------- solutions page: one horizontal band per solution ---------- */
.solution-band{padding:clamp(56px,7vw,100px) 0;background:var(--paper);
  border-top:1px solid var(--line-soft);scroll-margin-top:96px}
.solution-band.alt{background:var(--paper-2)}
.solution-inner{display:grid;grid-template-columns:minmax(0,1fr) minmax(0,2fr);
  gap:clamp(28px,5vw,80px);align-items:center;max-width:1200px;margin:0 auto;padding:0 var(--gut)}
.solution-band .solution-mark{width:clamp(180px,20vw,280px);justify-self:start}
.solution-band.alt .solution-inner{grid-template-columns:minmax(0,2fr) minmax(0,1fr)}
.solution-band.alt .solution-mark{order:2;justify-self:end}
.solution-copy h2{font-family:var(--display);font-size:clamp(1.75rem,3vw,2.5rem);color:var(--navy);
  line-height:1.15;margin-bottom:18px}
.solution-copy p{color:var(--muted);font-size:1.0625rem;line-height:1.7;max-width:var(--measure)}
.solution-copy p+p{margin-top:14px}
.solution-copy .eyebrow{margin-bottom:16px}

/* ---------- section scaffolding ---------- */
.band{padding:clamp(48px,6vw,96px) 0}
.eyebrow{display:flex;align-items:baseline;gap:12px;font-size:.75rem;letter-spacing:.14em;
  text-transform:uppercase;color:var(--dim);margin-bottom:22px}
.eyebrow b{color:var(--accent);font-weight:700;font-variant-numeric:tabular-nums}
.lede{color:var(--muted);font-size:clamp(1rem,1.25vw,1.125rem);max-width:60ch}
.lede+.lede{margin-top:18px}

/* ---------- inner page head: a navy band, like the hero ---------- */
.page-head{background:var(--navy-deep);color:var(--on-navy);
  padding:clamp(56px,8vw,120px) 0 clamp(48px,6vw,90px)}
.page-head h1{font-family:var(--display);font-size:clamp(2.25rem,5vw,4.25rem);line-height:1.06;
  letter-spacing:-.5px;color:var(--pale);max-width:18ch}
.page-head .lede{margin-top:clamp(20px,2.4vw,32px);color:var(--on-navy);
  font-size:clamp(1.0625rem,1.3vw,1.25rem)}
.page-head .eyebrow{color:var(--sky);margin-bottom:26px}
.page-head .eyebrow b{color:var(--pale)}
.page-head .tags{margin-top:24px}
.page-head .tags li{border-color:#ffffff44;color:var(--pale)}
.page-head-contact{padding:clamp(44px,4vw,58px) 0 clamp(44px,4vw,58px)}

/* ---------- projects: one card per project ---------- */
.project-cards{display:grid;grid-template-columns:repeat(auto-fill,minmax(280px,1fr));gap:clamp(20px,2.4vw,32px)}
.project-card{position:relative;display:flex;flex-direction:column;background:#fff;
  border:1px solid var(--line);border-radius:var(--radius);overflow:hidden;
  transition:transform var(--dur) var(--ease),box-shadow var(--dur) var(--ease),border-color var(--dur) var(--ease)}
.project-card:hover{transform:translateY(-4px);box-shadow:0 18px 40px -22px #000f4766;border-color:var(--sky)}
.card-head{background:var(--navy-deep);color:var(--pale);min-height:150px;padding:22px 24px;
  display:flex;flex-direction:column;justify-content:space-between;gap:12px}
.card-num{font-family:var(--display);font-size:2.5rem;line-height:1;color:var(--pale)}
.card-kicker{font-size:.75rem;letter-spacing:.14em;text-transform:uppercase;color:var(--sky)}
.card-body{padding:22px 24px 26px;display:flex;flex-direction:column;gap:12px;flex:1}
.card-body h2{font-family:var(--display);font-size:1.375rem;line-height:1.25;color:var(--navy)}
.card-body h2 a:after{content:"";position:absolute;inset:0}
.card-body p:not(.learn){color:var(--muted);font-size:.9375rem;line-height:1.6;flex:1}
.project-card:hover h2{color:var(--accent)}
.tags{display:flex;flex-wrap:wrap;gap:8px}
.tags li{font-size:.75rem;letter-spacing:.04em;color:var(--muted);border:1px solid var(--line);padding:6px 11px;
  border-radius:999px}

.tags-sm{gap:6px;margin-top:2px}
.tags-sm li{font-size:.6875rem;padding:4px 9px;color:var(--dim)}

/* ---------- project mark ----------
   The slot each project's artwork drops into. It reserves the same box whether it
   holds an image, a canvas, or nothing at all, so filling one in later never changes
   a card's height. Absolutely positioned for exactly that reason: the head band's
   own layout cannot be pushed around by what lands here.
   --orb-dot / --orb-glow are read by the runtime, so the palette stays in this file. */
.mark{position:absolute;aspect-ratio:1;pointer-events:none;
  --orb-dot:var(--sky);--orb-glow:var(--pale)}
.mark img,.mark canvas{display:block;width:100%;height:100%}
/* The resting state, and the fallback whenever the runtime does not paint: a ring
   quoting the solution mark's ring, so an unfilled slot reads as designed, not as a gap. */
.mark-empty:before{content:"";position:absolute;inset:0;border-radius:50%;
  border:1px solid #95caff40;background:radial-gradient(circle at 50% 50%,#95caff1f,transparent 70%)}
.mark-lg{width:clamp(120px,13vw,180px);right:0;top:50%;transform:translateY(-50%)}

.card-head{position:relative}
/* The numeral and the mark share the top line, so cap the numeral's width or a
   wide mark and a wide numeral collide at the narrow end of the grid. */
.card-head .card-num{position:relative;z-index:1}

/* ---------- projects: one horizontal band per project ----------
   The same pattern as the Solutions page, for the same reason it was chosen there.
   A grid could not hold seven projects: every column count left one card stranded
   on a row of its own. The card rules above stay, because the 404 page still
   renders its sections as cards.

   Pointing at a band sets its orb moving; the runtime binds the hover to
   .project-band and stops the loop again when the pointer leaves. */
.project-band{padding:clamp(44px,5.5vw,76px) 0;background:var(--paper);
  border-top:1px solid var(--line-soft);scroll-margin-top:96px;position:relative}
.project-band.alt{background:var(--paper-2)}
.project-inner{display:grid;grid-template-columns:minmax(0,1fr) minmax(0,2fr);
  gap:clamp(28px,5vw,80px);align-items:center;max-width:1200px;margin:0 auto;padding:0 var(--gut)}
.project-band.alt .project-inner{grid-template-columns:minmax(0,2fr) minmax(0,1fr)}
.project-band.alt .mark{order:2;justify-self:end}

.project-copy h2{font-family:var(--display);font-size:clamp(1.625rem,2.8vw,2.25rem);color:var(--navy);
  line-height:1.15;margin-bottom:14px;transition:color var(--dur) var(--ease)}
.project-copy h2 a:after{content:"";position:absolute;inset:0}
.project-band:hover h2,.project-band:focus-within h2{color:var(--accent)}
/* Exclude the eyebrow, the outcome and the link, or this type selector outranks
   their own class rules and flattens all four into one grey paragraph. */
.project-copy>p:not(.eyebrow):not(.learn):not(.outcome){color:var(--muted);font-size:1.0625rem;
  line-height:1.7;max-width:var(--measure)}
.project-copy .outcome{color:var(--navy);font-size:.9375rem;line-height:1.6;margin-top:16px;
  border-left:2px solid var(--pale);padding-left:14px;max-width:var(--measure)}
.project-copy .tags{margin-top:16px}
.project-copy .learn{margin-top:18px;color:var(--accent);font-size:.9375rem}
.project-band:hover .arrow,.project-band:focus-within .arrow{transform:translateX(5px)}

/* In a band the mark is a grid cell, not an overlay, so undo the absolute placement
   the page head needs. It also sits on paper here rather than navy: sky alone is
   too faint against a light ground, so the bright dots move to the accent blue.
   The width deliberately matches .solution-band .solution-mark: both pages put their graphic
   in the same grid cell, and a smaller mark made Projects read as the lighter page. */
.project-band .mark{position:relative;width:clamp(180px,20vw,280px);right:auto;top:auto;
  transform:none;justify-self:start;
  --orb-dot:var(--sky);--orb-glow:var(--accent)}
.project-band .mark-empty:before{border-color:var(--line);
  background:radial-gradient(circle at 50% 50%,#0b4bff0f,transparent 70%)}

@media(max-width:820px){
  .project-inner,.project-band.alt .project-inner{grid-template-columns:minmax(0,1fr);gap:22px}
  .project-band.alt .mark{order:0;justify-self:start}
  .project-band .mark{width:clamp(150px,30vw,200px)}
}

.page-head-mark .shell{position:relative}
/* Project heads carry the mark, which already sets their height; a third less padding
   brings the facts strip up toward the fold without shrinking the artwork. */
.page-head-mark{padding:clamp(40px,5.4vw,80px) 0 clamp(32px,4vw,60px)}
/* Keep the head's text out from under the mark. Without this the tag row, which is
   the widest line and wraps with the content, slides beneath it at some widths. */
@media(min-width:901px){
  .page-head-mark .shell{--head-mark-size:clamp(260px,29vw,440px);
    padding-right:calc(var(--head-mark-size) + var(--gut) + 40px);
    min-height:calc(var(--head-mark-size) - 48px)}
  /* Case studies: less padding and a shorter min-height, so the facts strip reaches the
     fold; the mark spills into the padding instead of adding to the height. Desktop only:
     below 901px the mark is hidden and .page-head-mark's padding is already smaller. */
  .page-head-case{padding:clamp(44px,3.5vw,56px) 0 clamp(42px,3.2vw,50px)}
  /* The head padding is at least 86px, so this keeps the whole mark inside the navy band
     even now the summary and tags are gone and the text no longer sets the height. */
  .page-head-case .shell{min-height:calc(var(--head-mark-size) - 80px)}
  .page-head-mark .mark-lg{width:var(--head-mark-size);right:var(--gut)}
  /* White artwork has enough contrast on navy even at the smallest dot sizes. */
  .page-head-mark .mark img{filter:brightness(0) invert(1)}
}
/* Only the detail page's head mark drops out here. The projects bands use the same
   size class and must keep theirs, so this stays scoped to .page-head. */
@media(max-width:900px){.page-head .mark-lg{display:none}}
@media print{.page-head-mark .mark img{filter:none}}

/* ---------- natpar ---------- */
.natpar{display:grid;grid-template-columns:minmax(0,1fr) minmax(0,1fr);gap:clamp(24px,4vw,64px)}
.doc-card{border:1px solid var(--line);border-radius:var(--radius);padding:clamp(24px,2.4vw,36px);
  display:flex;flex-direction:column;gap:18px;align-items:flex-start;background:#fff}
.doc-card h2{font-family:var(--display);font-size:1.5rem;color:var(--navy)}
.meta{font-size:.8125rem;color:var(--dim)}

/* ---------- contact ---------- */
.band-contact{padding:clamp(32px,4vw,56px) 0}
.contact-layout{display:grid;grid-template-columns:minmax(0,1.2fr) minmax(320px,.8fr);
  gap:clamp(20px,2.4vw,32px);align-items:stretch}
.contact-main,.contact-guide{border:1px solid var(--line);border-radius:var(--radius);
  padding:clamp(24px,3vw,42px)}
.contact-main{background:var(--paper-2);border-left:4px solid var(--accent)}
.contact-layout .eyebrow{color:var(--accent);margin-bottom:20px}
.contact-layout h2{font-family:var(--display);font-size:clamp(1.75rem,2.6vw,2.25rem);
  line-height:1.16;color:var(--navy);margin-bottom:18px}
.contact-main>p:not(.eyebrow):not(.contact-address){color:var(--muted);font-size:1.0625rem;
  line-height:1.65;max-width:54ch}
.contact-actions{display:flex;flex-wrap:wrap;gap:14px;margin-top:30px}
.contact-address{color:var(--dim);font-size:.8125rem;margin-top:18px;overflow-wrap:anywhere}
.contact-address span{color:var(--navy);font-weight:600}
.contact-guide li{border-top:1px solid var(--line-soft);padding:12px 0;color:var(--navy)}
.contact-guide li:last-child{border-bottom:1px solid var(--line-soft)}
.contact-person{color:var(--muted);font-size:.9375rem;line-height:1.6;margin-top:24px}
.contact-person .more{margin-left:4px}

/* ---------- leadership ---------- */
.people{display:grid;grid-template-columns:repeat(3,1fr);gap:clamp(24px,3vw,48px)}
.person{padding:clamp(24px,2.6vw,40px);border:1px solid var(--line);border-radius:var(--radius);background:#fff}
.person h2{font-family:var(--display);font-size:1.75rem;color:var(--navy)}
.person .role{font-size:.75rem;letter-spacing:.14em;text-transform:uppercase;color:var(--accent);margin:10px 0 20px}
.person p{color:var(--muted);font-size:.9375rem;line-height:1.65}
.person p+p{margin-top:14px}
.person .portrait{display:block;width:100%;max-width:210px;height:auto;border-radius:var(--radius);
  border:1px solid var(--line);margin-bottom:22px}

/* ---------- footer: navy, like the hero ---------- */
.site-footer{background:var(--navy-deep);color:var(--on-navy);padding:clamp(40px,5vw,72px) 0 40px}
.site-footer .shell{display:grid;grid-template-columns:minmax(0,1.2fr) minmax(0,1fr) minmax(0,1fr);gap:clamp(24px,3vw,48px)}
.site-footer .wordmark{color:#fff;margin:-8px 0 -9px}
/* Accent blue on navy is 2.6:1; the period vanished on exactly the surface where the
   wordmark should read. Sky on navy is 9:1. */
.site-footer .brand-period{color:var(--sky)}
.site-footer h2{font-size:.75rem;letter-spacing:.14em;text-transform:uppercase;color:var(--sky);margin-bottom:6px}
/* Footer links are stacked, so their hit areas cannot overlap: the list has to open up
   to 44px per row rather than borrow space with negative margins. The heading margin
   above shrinks by the same amount the first link's padding adds. */
.site-footer li+li{margin-top:0}
.site-footer a{color:var(--on-navy)}
/* Scoped to the sitemap: the footer wordmark is an <a> too, and already reaches 44px
   through its own min-height. */
.site-footer li a{display:inline-block;padding:12px 0}
.site-footer a:hover{color:#fff}
.site-footer .small{font-size:.8125rem;color:#b7c4dc;line-height:1.6;margin-top:16px;max-width:38ch}
.colophon{background:var(--navy-deep);color:#a9b8d6;border-top:1px solid #ffffff22;padding:24px 0 48px;
  font-size:.75rem;line-height:1.7}
.colophon .shell{display:flex;gap:18px;flex-wrap:wrap;justify-content:space-between}
.disclosure{border-left:2px solid #ffffff33;padding-left:16px;max-width:70ch}

/* ---------- section pager ---------- */
.pager{display:grid;grid-template-columns:1fr 1fr;border-top:1px solid var(--line)}
.pager a{padding:clamp(24px,2.6vw,40px) var(--gut);display:flex;flex-direction:column;gap:10px}
.pager a+a{border-left:1px solid var(--line);text-align:right;align-items:flex-end}
.pager a:only-child{grid-column:1 / -1}
.pager a.next{text-align:right;align-items:flex-end}
/* Project pages: the return link sits inside the nav, directly after the figures. */
.band-case{padding-bottom:clamp(32px,4vw,56px)}
.band-case.case-study{padding-top:clamp(24px,2.4vw,36px)}
.project-nav{border-top:1px solid var(--line)}
.all-projects{display:inline-flex;align-items:center;gap:10px;min-height:44px;padding:10px 0;font-size:.75rem;
  letter-spacing:.14em;text-transform:uppercase;font-weight:600;color:var(--accent)}
.all-projects:hover{color:var(--navy)}
.pager a:hover{background:var(--paper-2)}
.pager span{font-size:.75rem;letter-spacing:.14em;text-transform:uppercase;color:var(--dim)}
.pager b{font-family:var(--display);font-weight:400;font-size:clamp(1.25rem,2vw,1.75rem);line-height:1.1;color:var(--navy)}
.pager a:hover b{color:var(--accent)}

/* ---------- project detail pages ---------- */
.crumbs{padding:16px 0;
  border-bottom:1px solid var(--line-soft);font-size:.75rem;letter-spacing:.14em;
  text-transform:uppercase;color:var(--dim)}
.crumbs .shell{display:flex;flex-wrap:wrap;gap:12px;align-items:baseline}
.crumbs a:hover{color:var(--accent)}
.crumbs [aria-current]{color:var(--navy)}
.crumbs .sep{color:var(--line)}

.article-row{display:grid;grid-template-columns:minmax(0,20ch) minmax(0,1fr);
  gap:clamp(24px,4vw,64px);padding:clamp(28px,3vw,48px) 0;border-bottom:1px solid var(--line-soft)}
.article-row:first-child{padding-top:0}
.article-row:last-child{border-bottom:0}
.article-row h2{font-family:var(--display);font-size:1.625rem;line-height:1.2;color:var(--navy)}
.case-study .article-row h2{font-size:clamp(1.75rem,2.4vw,2.25rem)}
.article-copy p{color:var(--muted);font-size:1.0625rem;line-height:1.75;max-width:var(--measure)}
.article-copy p+p{margin-top:16px}

/* Case-study layers (projectPage). auto-fit so two facts and five both fill the row. */
.facts{display:grid;grid-template-columns:repeat(auto-fit,minmax(160px,1fr));gap:1px;
  background:var(--line);border:1px solid var(--line);border-radius:var(--radius);overflow:hidden;
  margin-bottom:clamp(20px,2.4vw,32px)}
.facts div{background:var(--paper-2);padding:18px 20px}
.facts dt{font-size:.6875rem;letter-spacing:.14em;text-transform:uppercase;color:var(--dim);margin-bottom:6px}
.facts dd{margin:0;color:var(--navy);font-weight:600;line-height:1.35}
.brief{background:var(--paper-2);border-left:4px solid var(--accent);border-radius:var(--radius);
  padding:clamp(20px,2.4vw,32px);margin-bottom:clamp(36px,4vw,56px)}
/* One sentence per line, so a wider measure than body copy; still capped. */
.brief p{color:var(--ink);font-size:1.125rem;line-height:1.65;max-width:100ch}
.brief p+p{margin-top:12px}
.brief strong{font-weight:700;color:var(--navy)}
.row-n{display:block;font-family:var(--text);font-size:.75rem;letter-spacing:.14em;color:var(--accent);
  font-weight:700;font-variant-numeric:tabular-nums;margin-bottom:10px}
.case-study .row-n{display:grid;place-items:center;width:36px;height:36px;margin-bottom:14px;
  border-radius:50%;background:var(--paper-2);letter-spacing:0}
.article-copy .row-lead{color:var(--ink);font-size:1.1875rem;line-height:1.6}
/* Rows after the figures: the figures sit between two runs of article rows. */
.article-after{margin-top:clamp(36px,4vw,56px)}
.terms{display:grid;grid-template-columns:repeat(auto-fit,minmax(min(240px,100%),1fr));gap:18px 32px;max-width:var(--measure)}
.terms dt{font-weight:600;color:var(--navy);margin-bottom:4px}
.terms dd{margin:0;color:var(--muted);line-height:1.6}
.points{list-style:none;display:grid;gap:10px;margin:18px 0 20px;padding:0;max-width:var(--measure)}
.points li{position:relative;padding:12px 16px 12px 38px;border:1px solid var(--line);border-radius:var(--radius);
  background:#fff;color:var(--muted);line-height:1.5}
.points li strong{color:var(--navy);font-weight:700}
.points li:before{content:"";position:absolute;left:16px;top:1.15em;width:7px;height:7px;border-radius:50%;
  background:var(--accent)}
/* Case studies read at the reference's width: one balanced two-column article of about
   1120px, with the bullet cards filling their column instead of stopping at the measure. */
.case-study .article{max-width:1120px}
.case-study .points{max-width:none}
/* "Read more": the lead and bullets stay visible; the method detail opens on demand. */
.more-detail{margin-top:20px;background:var(--paper-2);border:1px solid var(--line);border-radius:var(--radius)}
.more-detail summary{display:flex;align-items:center;justify-content:space-between;gap:16px;min-height:48px;
  padding:12px 18px;cursor:pointer;list-style:none;font-weight:600;color:var(--navy)}
.more-detail summary::-webkit-details-marker{display:none}
.more-detail summary:after{content:"+";display:grid;place-items:center;flex:0 0 28px;height:28px;
  border:1px solid var(--line);border-radius:50%;background:#fff;color:var(--accent);font-weight:400}
.more-detail[open] summary:after{content:"−"}
.more-detail summary:hover{color:var(--accent)}
.article-copy .more-detail p{padding:0 18px}
.article-copy .more-detail p:last-child{padding-bottom:18px}
.figs-heading{font-family:var(--display);font-size:clamp(1.5rem,2vw,1.875rem);line-height:1.2;color:var(--navy);
  margin-top:clamp(36px,4vw,56px)}
.case-contact{display:grid;grid-template-columns:minmax(0,20ch) minmax(0,1fr);
  gap:clamp(24px,4vw,64px);margin-top:clamp(32px,4vw,56px)}
.case-contact p{grid-column:2;color:var(--navy);font-size:1.125rem}
.case-contact a{color:var(--accent);font-weight:600;margin-left:8px;white-space:nowrap}
.case-contact a:hover{color:var(--navy)}

/* auto-fit so a single-figure page gets one full-width cell rather than an empty second one */
.fig-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(520px,1fr));gap:24px;
  margin-top:clamp(24px,3vw,40px)}
.fig{background:#fff;border:1px solid var(--line);border-radius:var(--radius);padding:clamp(16px,1.6vw,24px);
  transition:border-color var(--dur) var(--ease)}
.fig:hover{border-color:var(--sky)}
.fig img{display:block;width:100%;height:auto}
/* Drawn charts: past this width the text only gets bigger, not clearer. */
.fig img.fig-chart{max-width:720px;margin-inline:auto}
.fig .fig-n{font-size:.75rem;letter-spacing:.14em;text-transform:uppercase;color:var(--accent);margin-bottom:14px}
.fig figcaption{margin-top:14px;font-size:.8125rem;color:var(--muted);line-height:1.6;max-width:var(--measure)}
.fig-credit{display:block;margin-top:6px;color:var(--dim)}


/* ---------- hover and press states ----------
   Colour, the arrow glyph, and at most a few px of travel. Nothing changes its box. */
a,button{transition:color var(--dur) var(--ease),
                    background-color var(--dur) var(--ease),
                    border-color var(--dur) var(--ease)}
.arrow{display:inline-block;will-change:transform;transition:transform var(--dur) var(--ease)}
a:hover .arrow,a:focus-visible .arrow,
.project-card:hover .arrow,.solution-card:hover .arrow{transform:translateX(5px)}

.primary{transition:background-color var(--dur) var(--ease),transform var(--dur) var(--ease)}
.primary:hover,.primary:focus-visible{background:var(--accent-soft);transform:translateY(-2px)}
.primary:active{transform:translateY(0);transition-duration:60ms}

.ghost{transition:color var(--dur) var(--ease),border-color var(--dur) var(--ease),
                  background-color var(--dur) var(--ease),transform var(--dur) var(--ease)}
.ghost:hover,.ghost:focus-visible{background:var(--navy);border-color:var(--navy);color:#fff}
.ghost-light:hover,.ghost-light:focus-visible{background:var(--pale);border-color:var(--pale);color:var(--navy)}
.ghost:active{transform:translateY(1px);transition-duration:60ms}

.nav-toggle:hover{border-color:var(--accent);color:var(--accent)}
.nav-toggle:active{transform:translateY(1px)}

/* Nav: an underline that grows from the leading edge instead of appearing whole. */
.site-nav a:after{content:"";position:absolute;left:0;right:0;bottom:6px;height:2px;
  background:var(--accent);transform:scaleX(0);transform-origin:left;
  transition:transform var(--dur-slow) var(--ease-out)}
.site-nav a:hover:after,.site-nav a:focus-visible:after{transform:scaleX(1)}
.site-nav a[aria-current]:after{transform:scaleX(1)}

.pager a{transition:background-color var(--dur) var(--ease)}
.pager a b{display:inline-block;transition:color var(--dur) var(--ease),transform var(--dur-slow) var(--ease-out)}
.pager a:first-child:hover b{transform:translateX(-5px)}
.pager a+a:hover b,.pager a.next:hover b{transform:translateX(5px)}
.skip{transition:top var(--dur-slow) var(--ease-out)}

@media(hover:none){
  .primary:hover,.ghost:hover,.project-card:hover,.solution-card:hover .solution-mark{transform:none}
}

/* ---------- responsive ---------- */
@media(min-width:1700px){
  .hero-inner{min-height:835px;padding:62px 40px}
  .hero-stage{left:30%;top:180px}
  .hero-copy{max-width:440px}
  .hero-copy h2{font-size:2.25rem}
  .intro{font-size:1.125rem}
}
@media(max-width:1150px){
  .site-nav{gap:26px}
  .hero-inner{min-height:760px}
  .hero-stage{inset:155px -70px -40px 30%}
  .hero-copy{margin-top:200px}
  .people{grid-template-columns:1fr 1fr}
  .natpar{grid-template-columns:1fr}
  /* The grid is on .shell, not .site-footer; these two rules used to miss it. */
  .site-footer .shell{grid-template-columns:minmax(0,1fr) minmax(0,1fr)}
  .site-footer .shell>:first-child{grid-column:1 / -1}
}
@media(max-width:1000px){
  .solution-grid{grid-template-columns:1fr 1fr}
}
@media(max-width:900px){
  .solution-inner,.solution-band.alt .solution-inner{grid-template-columns:1fr}
  .solution-band.alt .solution-mark{order:0;justify-self:start}
  .solution-band .solution-mark{width:clamp(150px,30vw,200px)}
  .article-row{grid-template-columns:minmax(0,1fr);gap:14px}
  .case-contact{grid-template-columns:minmax(0,1fr)}
  .case-contact p{grid-column:1}
  .fig-grid{grid-template-columns:1fr}
  .pager{grid-template-columns:1fr}
  .pager a+a{border-left:0;border-top:1px solid var(--line);text-align:left;align-items:flex-start}
  .pager a.next{text-align:left;align-items:flex-start}
}
@media(max-width:850px){
  .site-header{padding:18px var(--gut);min-height:80px;flex-wrap:wrap}
  .wordmark{font-size:1.5rem}
  /* Without JS the nav stays stacked and visible; the toggle only appears when JS can drive it. */
  .js .nav-toggle{display:block}
  .site-nav{width:100%;flex-direction:column;align-items:stretch;gap:0;border-top:1px solid var(--line);margin-top:4px}
  .js .site-nav{display:none}
  .js .site-nav[data-open="true"]{display:flex}
  .site-nav a{padding:16px 2px;border-bottom:1px solid var(--line-soft)}
  .site-nav a:after{display:none}
  .hero-inner{padding:36px var(--gut) 38px;min-height:750px}
  .hero-stage{inset:160px -65px 70px 27%;opacity:.85}
  .hero-copy{max-width:320px;margin-top:220px}
  .hero-copy h2{font-size:1.75rem}
  .site-footer .shell{grid-template-columns:minmax(0,1fr)}
  .contact-layout{grid-template-columns:minmax(0,1fr)}
}
@media(max-width:650px){
  .facts{grid-template-columns:1fr}
  .hero-inner{padding:30px var(--gut) 32px;min-height:750px;justify-content:flex-start}
  .hero h1{letter-spacing:-.3px;text-align:left;align-self:flex-start}
  .hero-stage{inset:145px 0 238px 0;opacity:.9}
  .hero-stage img,.hero-stage canvas{transform:none}
  .hero-copy{margin-top:292px;max-width:300px}
  .hero-copy h2{font-size:1.875rem}
  .solution-grid{grid-template-columns:1fr}
  .solution-card .solution-mark{width:140px}
  .people{grid-template-columns:1fr}
  .colophon{flex-direction:column}
}

@media(prefers-reduced-motion:reduce){
  html{scroll-behavior:auto}
  *,*:before,*:after{animation-duration:.001ms!important;animation-iteration-count:1!important;
    transition-duration:.001ms!important;scroll-behavior:auto!important}
}

/* ---------- page transitions ----------
   Native cross-document view transitions where supported; a CSS/JS fade elsewhere.
   Opacity only — nothing slides, and the headline hierarchy is never animated. */
@view-transition{navigation:auto}
@keyframes page-in{from{opacity:0}to{opacity:1}}
@keyframes page-out{from{opacity:1}to{opacity:0}}
::view-transition-old(root){animation:page-out 180ms ease both}
::view-transition-new(root){animation:page-in 280ms ease both}
/* Fallback for browsers without cross-document view transitions (Safari, Firefox).
   The inline head script adds .no-vt before first paint when @view-transition is
   unsupported; site.js then adds .is-leaving just before it navigates. */
html.no-vt body{animation:page-in 280ms ease both}
html.no-vt.is-leaving body{animation:page-out 180ms ease both}
@media(prefers-reduced-motion:reduce){
  ::view-transition-old(root),::view-transition-new(root){animation:none}
  html.no-vt body,html.no-vt.is-leaving body{animation:none}
}

/* ---------- print ---------- */
@media print{
  .more-detail summary{display:none}
  .more-detail{background:none;border:0}
  .facts,.brief,.points li,.terms div{break-inside:avoid}
  .facts div{background:#fff}
  body{background:#fff;color:#000f47;animation:none}
  .site-header,.nav-toggle,.hero-stage,.skip,.pager,.project-nav,.crumbs,.mark,
  .solution-mark{display:none}
  .hero,.page-head,.card-head,.site-footer,.colophon{background:#fff;color:#000f47}
  .hero h1,.page-head h1,.page-head .lede,.page-head .eyebrow,.page-head .eyebrow b,.hero-copy h2,.intro,
  .card-num,.card-kicker,.site-footer a,.site-footer h2,.colophon{color:#000f47}
  .hero-inner,.band,.page-head,.explore,.solution-band,.project-band{padding:24px 0;min-height:0}
  .hero h1,.page-head h1{font-size:2.5rem;text-align:left;align-self:flex-start;text-shadow:none}
  .hero-copy{margin-top:24px;max-width:none}
  .primary,.ghost{border:1px solid #000f47;background:#fff;color:#000f47}
  .solution-band.alt,.project-band.alt{background:#fff}
  .solution-grid,.project-cards,.people{grid-template-columns:1fr}
  .project-card,.fig,.person,.doc-card{border-color:#000f47;box-shadow:none}
  .fig{break-inside:avoid}
  .lede,.solution-copy p,.project-copy p,.article-copy p,.card-body p,.person p,
  .fig figcaption{color:#000f47}
}
