/* SMALL TYPE GROWS WITH THE SCREEN — 2026-08-08.
 *
 * The client's two observations were one fault: "有些字太小了" on a 4K screen,
 * and "保持长宽不变，整体缩小就整体缩小". Measured: this stylesheet had 349
 * vw-clamps and EVERY ONE of them stops growing before 3840 — the design is
 * fluid to about 1400-1900 and frozen after that — while the small labels
 * (eyebrows, dates, roles, filter captions, cookie buttons, review bylines)
 * were flat pixel values that never grew at all. On a 4K screen the big type
 * is frozen and the small type is a third the size it should be, which is why
 * the proportions read as broken.
 *
 * A global `zoom` was tried first and rejected with evidence: at 3840 with
 * zoom 2.29 the layout width stays 3840 and the page overflows sideways by
 * 1600px, because `zoom` does not shrink the layout viewport and every vw in
 * here still resolves against the full width. A vw-driven layout and a global
 * zoom cannot both be true.
 *
 * So the values grow instead. Each small size becomes
 * `clamp(<old>, <old/16.8>vw, <old*1.8>)`: the vw term equals the old value at
 * exactly 1680, so **nothing below 1680 changes by a single pixel** — the
 * laptop rendering the client already approved is untouched — and above it the
 * label scales with the screen to 1.8x, reaching its cap around 3020.
 */
/* MINIMUM TYPE SIZE: 12px — set 2026-08-08 at the client's request.
 *
 * "有些字太小了，可能丧失可读性。对于字的大小方面，这个应该是有明确要求的."
 *
 * The rule is: NO RENDERED TEXT ON THIS SITE IS SMALLER THAN 12px. Measured
 * before it existed, nine public pages carried text at 9, 9.5, 10, 10.5 and 11
 * — 79 declarations in all — and most of it was the letter-spaced small-caps
 * this design leans on: eyebrows, dates, roles, filter labels, the cookie
 * buttons, the review attributions. Small caps at 10px with 0.12em of tracking
 * looks composed on a designer's screen and is genuinely hard to read on a
 * laptop at arm's length, which is where a client reads it.
 *
 * 12px is the floor, not a target: anything already larger is untouched. If a
 * label no longer fits its column at 12px, the column is what changes.
 */
:root {
  --paper: #f2eee6;
  --paper-bright: #fbfaf6;
  --ink: #181917;
  --ink-soft: #282a27;
  --muted: #6b6962;
  --line: rgba(24, 25, 23, 0.18);
  --line-light: rgba(255, 255, 255, 0.18);
  --gold: #a07b45;
  --orange: #c9613d;
  /* The rotating quotation's ink, and the colour it warms to under the cursor.
     hero-wisdom.js reads all three from here — it writes `style.color` on every glyph on
     every frame, so a `color` declaration on the element alone cannot reach the screen.
     That is how the near-black survived a change from `--quote-ink` to `--ink` on
     `.hero-quote`: the declaration moved and the engine kept writing over it.
     #3a352e rather than #211f1c — clearly lighter, and lighter type at 68px reads as
     considered where black reads as default. Not lighter still: the tail of the longest
     quotations crosses the painting's mid-toned side, where the near-black already held
     only 2.53:1 against the 3:1 large text needs. That is a pre-existing weakness this
     colour must not deepen, and the honest fix for it is the composition — keeping the
     line off the dark third — rather than a wash over the artwork. Two washes were
     tried and both read as a panel; see the note by .hero-quote's text-shadow. */
  --quote-ink: #3a352e;
  --quote-ink-zh: #57534a;
  /* Deeper than the site's --gold (#a07b45), and the difference is a requirement rather
     than a preference. Gold's luminance sits in the middle of the range, and the tail of
     a long quotation crosses the painting's mid-toned side — at the site's #a07b45 the
     glyph a visitor is pointing at is the one that washes out, which is visible on
     screen and not only in the arithmetic. This is deep enough to hold there and still
     reads as the same family. */
  --quote-warm: #7a5a2c;
  /* WHAT THE CURSOR'S LIGHT DOES TO THE INK — warm, and only a little lighter.
     This was #606c7c, a cool blue-grey, and the client's correction was that the
     white should be warm rather than blue. #7c7060 is its mirror: the same
     lightness, the hue carried across the neutral instead of away from it, so
     the change is in colour temperature only and nothing about the legibility
     moved. It holds 4.4:1 on the painting's cream at full strength, against the
     3:1 large-type minimum.
     It is NOT white, and must not become white: the cream runs across the left
     two thirds of the artwork, which is where most of every quotation sits, and
     type carried to white there disappears. The white is in the glow on the
     letter — see .hero-quote__burn-glyph — not in the letter. --quote-warm
     above is the gold both of these replaced; nothing reads it now. */
  /* Read by nothing since the spotlight was withdrawn. Kept, with --quote-warm
     above it, because these two record what the lit state was when there was one:
     #7c7060 warmed to #998a76 at the measured 3:1 ceiling for near-white paper.
     Deleting them would leave d79 and d81 describing values that no longer exist
     anywhere. */
  --quote-lit: #998a76;
  --serif: "Iowan Old Style", Baskerville, "Times New Roman", serif;
  --sans: "Avenir Next", "Helvetica Neue", Arial, sans-serif;
  /* PHONE TYPE SCALE — approved on Contact and shared by every public route.
   *
   * The six numbers live here because Contact, People and the editorial
   * templates all express the same hierarchy. Route styles decide which
   * element has which role; they must not keep separate copies of the scale. */
  --phone-type-label: 12px;
  --phone-type-body: 15px;
  --phone-type-control: 16px;
  --phone-type-subheading: 20px;
  --phone-type-heading: 26px;
  --phone-type-display: clamp(48px, 13.333vw, 52px);
  --page: min(1460px, calc(100vw - var(--gutter-min) * 2));
  /* Reading band for everything below the hero — News, About, Expertise,
     Awards, Network, the closing banner. Narrower than --page on purpose: at
     --page those sections run to 89% of a 1440 screen, which reads as a web
     page rather than a publication. At the client's direction the band now
     holds them at the middle 70%: 15% whitespace on each side, 30% in total.
     The hero deliberately keeps --page; the first screen does not move.

     The inset is PROPORTIONAL first and capped second, and the order matters.
     A cap on its own (`(100vw - 880px) / 2`) is negative on any screen already
     narrower than the cap, so the max() falls straight through to --gutter-min
     and the band silently switches off — which is exactly what an iPad at 1024
     or 820 saw when this was a cap alone. The 15vw term is what actually holds
     70% on a tablet; the cap only takes over above ~2086px, where 15vw would
     start pushing the measure past the point where a line is comfortable to
     read, and from there the text stays at --band and the margin grows.

     --band-floor is the other end: below about 614px, 15vw would squeeze the
     measure under 430px, so the floor freezes the content width and lets the
     margin shrink instead. Under ~600px --gutter-min wins and the phone rules
     take over.

     THE CAP WAS 880px AND IT WAS TOO LOW — changed 2026-08-08, measured on the
     deployment rather than reasoned. The former 60% band only
     survived to about 1467px; above that it decayed to whatever 880 happened
     to be as a fraction: 45.8% at 1920, 34.4% at 2560, **22.9% at 3840**. On a
     4K screen the page read as a narrow strip with the masthead spanning far
     wider than the words underneath it.

     The old justification for 880 — that a wider band pushes the measure past
     comfortable reading — does not describe these sections. Measured inside
     the 880 band at 2560: the news cards are 440px, the About paragraphs 520
     and 592, the Awards list items 581. **Nothing runs the width of the band**,
     because every section below the hero has its own internal columns. The
     band is what those columns sit in, not the measure itself.

     1460px is not an arbitrary larger number: it is --header-rail, so above
     ~2433px the reading band and the masthead are the same width and the page
     reads as one column system instead of two that disagree. The former 20vw
     rule held 60% until that point. With the approved 30%-total whitespace,
     15vw holds the middle 70% until the same 1460px cap takes over at ~2086px. */
  --band: 1460px;
  --band-floor: 430px;
  --band-inset: max(
    var(--gutter-min),
    min(15vw, calc((100vw - var(--band-floor)) / 2)),
    calc((100vw - var(--band)) / 2)
  );
  /* The masthead is one global component. Route content may use its own rail,
     but the logo, navigation and search control must never move when a visitor
     changes page. */
  --header-rail: 1460px;
  /* The smallest side margin any full-width band may have.
   *
   * It was a flat 40px, and between about 1280 and 1600 that is all a page got: the
   * content rail is 1460, so on a 1512 laptop the arithmetic gives 26px and the floor
   * takes over at 40 — two and a half per cent of the screen, which reads as cramped
   * next to the same page on a large monitor where the rail leaves nearly a third.
   *
   * Tied to the viewport instead, so the breathing room a laptop gets is proportional
   * to the laptop. Above about 1730 the rail is already wider than this and nothing
   * changes — a 4K screen keeps exactly the margins it had. Capped at 120 so it cannot
   * outgrow the rail on an ultrawide, and the 40px minimum still holds under the
   * breakpoints where the media queries set their own padding. */
  --gutter-min: clamp(40px, 5.5vw, 120px);
  /* THE DESKTOP SIZE RAMP — read this before changing any length below.
   *
   * Type, vertical rhythm, component heights and grid gaps are written as
   * `clamp(floor, Xvw, authored)` where X = authored / 19.2. That coefficient is not
   * arbitrary: it makes the ramp reach its authored value at exactly 1920px and stay
   * there above it, so every large monitor renders the design at the size it was drawn
   * at, and a 1512 laptop gets the same design at 1512/1920 of that size.
   *
   * The ramps used to finish around 1500. A laptop and a 4K monitor were therefore
   * handed identical type and identical block heights — the same design occupying 2.2x
   * the share of the field of view on the smaller machine, which is what "the page looks
   * too big on my laptop" turned out to mean. The measured share of viewport width: the
   * hero title 28% on 4K against 61% on the laptop, the About paragraph 18% against 47%,
   * the network band a quarter of the screen height against two thirds.
   *
   * Each of these rules carries a nested `@media (max-width: 1180px)` restating its
   * original value. The ramp's floor is the value at 1180, which is not what the phone
   * and tablet breakpoints were composed against — without the restatement a paragraph
   * with no small-screen override would silently lose a third of its size. Anything in
   * the existing narrower media queries still wins over it, being later in the file.
   *
   * So: 1180 and below is hand-composed, 1181 to 1920 is the ramp, 1920 and above is the
   * authored design. Add a new length in the same form or it will not scale with its
   * neighbours. Horizontal padding is NOT part of this — it belongs to --gutter-min. */
  /* One height, at rest and scrolled alike. It used to open at 76px and shrink to 64
     on the first scroll — an effect nobody asked for that moved the whole page under
     the reader's eye twelve pixels the moment they touched the wheel. Fixed at the
     height it spent almost all its time at anyway.

     74 since 2026-08-11: the client asked for the masthead to grow by about 15%,
     and 64 x 1.15 is 73.6. It is ONE number for the whole site — every page that
     has to clear the bar writes `calc(var(--header-height) + …)` rather than a
     measured constant, nineteen times across four stylesheets, so this line is
     the only place the height exists and nothing can fall out of step with it. */
  --header-height: 74px;
  /* Promoted from the route stylesheets to `:root` so the shared chrome can
     texture itself. Same noise the page grounds use, so the header scrim is
     made of the same material as everything it sits on. */
  --grain: url("data:image/svg+xml,%3Csvg viewBox='0 0 180 180' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.9' numOctaves='3' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)' opacity='.45'/%3E%3C/svg%3E");
}

/* Cross-document navigation stays a normal multi-page load. Supporting browsers
   keep the outgoing pixels until the destination can paint, then develop only the
   last three per cent of the new frame over 110ms. There is no travel, blur, scale
   or theatrical overlay, and unsupported browsers simply use ordinary navigation. */
@view-transition {
  navigation: auto;
}

@keyframes yk-page-arrive {
  from { opacity: 0.97; }
  to { opacity: 1; }
}

::view-transition-group(root) {
  animation-duration: 110ms;
}

::view-transition-group(yk-site-header) {
  animation: none;
}

::view-transition-old(root) {
  animation: none;
  mix-blend-mode: normal;
}

::view-transition-new(root) {
  animation: yk-page-arrive 110ms ease-out both;
  mix-blend-mode: normal;
}

/* The shared chrome is continuity, not content. Snapshot it separately and swap
   it without animation so the logo and navigation never blink or drift while the
   route beneath them changes. */
::view-transition-old(yk-site-header),
::view-transition-new(yk-site-header) {
  animation: none;
  mix-blend-mode: normal;
}

* {
  box-sizing: border-box;
}

[hidden] {
  display: none !important;
}

html {
  background: var(--paper);
  scroll-behavior: smooth;
  /* The scrollbar's width is reserved permanently, whether or not a scrollbar is
     showing. `body.search-open` and `body.menu-open` below set overflow:hidden,
     which used to take the scrollbar away and hand its 15px back to the layout —
     and every artwork on the site is `background-size: cover`, so a 15px wider
     page rescaled all of them. Opening search on Legal Insights grew the opening
     artwork from 0.5938 to 0.6 of its natural size and closing it shrank the
     artwork back: a picture visibly breathing at the top of the page every time
     an overlay was used. Reserving the gutter means the two states are the same
     width, so nothing rescales. */
  scrollbar-gutter: stable;
  /* The header is fixed, so without this every in-page anchor lands its target's
     first line underneath it. On Contact the primary call to action scrolled the
     enquiry form's kicker entirely out of sight and sliced its headline in half.
     One declaration covers every anchor on every route. */
  scroll-padding-top: calc(var(--header-height) + 30px);
}

body {
  margin: 0;
  overflow-x: hidden;
  background: var(--paper);
  color: var(--ink);
  font-family: var(--sans);
  -webkit-font-smoothing: antialiased;
}

body.menu-open,
body.search-open {
  overflow: hidden;
}

button,
input {
  font: inherit;
}

button,
a {
  -webkit-tap-highlight-color: transparent;
}

img,
svg {
  display: block;
  max-width: 100%;
}

/* HOW EVERY PICTURE ON THIS SITE ARRIVES.
 *
 * One rule set, no page and no component owns a second copy, and no route has
 * to opt in: motion.js marks every <img> in the document — including the ones
 * later scripts append — and these five selectors are the whole treatment.
 * The head of that file explains the marking; the short version is that
 * nothing here matches until the script has taken charge of a picture, so a
 * failed or absent script leaves every picture visible and untouched.
 *
 * "wait" is a picture that has not arrived. It is invisible, which costs
 * nothing, because an unloaded image had nothing to show; the box that was
 * already holding its place carries the rest tint instead. "in" is the moment
 * it arrives: the picture fades up while the tint fades out under it, which is
 * a real cross-fade rather than a flash to transparent. The tint only ever
 * lands on a box that paints no background of its own, so `transparent`
 * afterwards restores precisely what was there.
 *
 * Tune the timing here and every picture on the site changes together. */
img[data-yk-img="wait"] {
  opacity: 0;
}

/* AN ANIMATION, NOT A TRANSITION, AND THAT IS NOT A STYLE PREFERENCE.
 * A transition only runs for properties named in the element's own
 * `transition-property`, and the roster's portraits already name
 * `transform, filter` for their hover treatment — which silently discarded an
 * opacity transition declared here and left 37 portraits snapping into place
 * while every measurement said "faded", because an instant jump also goes from
 * 0 to 1. An animation is not filtered by anybody's transition list.
 * `opacity: 1` is the resting value, so a picture stays visible even if the
 * animation never runs at all. */
img[data-yk-img="in"] {
  opacity: 1;
  animation: yk-picture-in 0.55s ease;
}

@keyframes yk-picture-in {
  from {
    opacity: 0;
  }
  to {
    opacity: 1;
  }
}

/* A BARE BOX gets a skeleton, because it has nothing of its own to show. */
[data-yk-img-box][data-yk-img-bare] {
  background-color: rgba(24, 25, 23, 0.055);
}

/* Same reasoning as the picture above, and `forwards` rather than `both`: the
   tint must end cleared, so that a logo with transparency is never left
   sitting on a wash, and must not be held before the animation starts. */
[data-yk-img-box="in"][data-yk-img-bare] {
  animation: yk-picture-box-out 0.8s ease 0.1s forwards;
}

@keyframes yk-picture-box-out {
  from {
    background-color: rgba(24, 25, 23, 0.055);
  }
  to {
    background-color: transparent;
  }
}

/* Only near the viewport — see the note by the observer in motion.js. */
[data-yk-img-box="wait"][data-yk-img-near][data-yk-img-bare] {
  background-image: linear-gradient(
    100deg,
    rgba(255, 255, 255, 0) 30%,
    rgba(255, 255, 255, 0.5) 50%,
    rgba(255, 255, 255, 0) 70%
  );
  background-repeat: no-repeat;
  background-size: 220% 100%;
  animation: yk-picture-sheen 1.65s linear infinite;
}

/* A BOX THAT IS ALREADY DRESSED breathes instead. The roster's portrait frames
   carry a designed gradient and the profile and article frames may too; a
   skeleton drawn over that would be a placeholder covering a placeholder. This
   moves what is already there and adds nothing. The range is deliberately
   shallow: the animation is dropped the instant the picture starts fading in,
   and a deep one would leave a visible step at that moment. */
[data-yk-img-box="wait"][data-yk-img-near]:not([data-yk-img-bare]) {
  animation: yk-picture-breathe 2.4s ease-in-out infinite;
}

@keyframes yk-picture-sheen {
  from {
    background-position: 155% 0;
  }
  to {
    background-position: -55% 0;
  }
}

@keyframes yk-picture-breathe {
  0%,
  100% {
    opacity: 1;
  }
  50% {
    opacity: 0.88;
  }
}

/* Reduced motion keeps the rest tint — a held place is information, not
   decoration — and drops every moving part of it. */
@media (prefers-reduced-motion: reduce) {
  img[data-yk-img="in"],
  [data-yk-img-box="wait"][data-yk-img-near]:not([data-yk-img-bare]) {
    animation: none;
  }

  /* The blanket rule further down this file shortens every animation to
     0.01ms, which would leave the sheen's gradient painted as a frozen streak
     and — because a cancelled `forwards` stops filling — the rest tint sitting
     under the picture for good. Both are stated here rather than left to it. */
  [data-yk-img-box="wait"][data-yk-img-near][data-yk-img-bare] {
    background-image: none;
    animation: none;
  }

  [data-yk-img-box="in"][data-yk-img-bare] {
    background-color: transparent;
    animation: none;
  }
}

a {
  color: inherit;
  text-decoration: none;
}

ul,
ol {
  margin: 0;
  padding: 0;
}

::selection {
  background: var(--orange);
  color: #fff;
}

:focus-visible {
  outline: 2px solid var(--orange);
  outline-offset: 4px;
}

.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;
}

.skip-link {
  position: fixed;
  z-index: 1000;
  top: 12px;
  left: 12px;
  padding: 10px 14px;
  transform: translateY(-150%);
  background: var(--ink);
  color: #fff;
  font-size: 12px;
}

.skip-link:focus {
  transform: translateY(0);
}

.site-header {
  position: fixed;
  z-index: 100;
  inset: 0 auto auto 0;
  width: 100vw;
  box-sizing: border-box;
  height: var(--header-height);
  /* One masthead rail on every route. The page below may be 1400, 1460 or
     1480px wide; none of those content decisions is allowed to move shared
     chrome during navigation. */
  padding: 0 max(var(--gutter-min), calc((100vw - var(--header-rail)) / 2));
  display: grid;
  grid-template-columns: 170px 1fr 40px;
  gap: clamp(16px, 1.35417vw, 26px);
  align-items: center;
  background-color: rgba(247, 245, 239, var(--header-frost-opacity, 0.12));
  backdrop-filter:
    blur(var(--header-blur, 5px))
    saturate(var(--header-frost-saturation, 1))
    brightness(var(--header-frost-brightness, 1));
  -webkit-backdrop-filter:
    blur(var(--header-blur, 5px))
    saturate(var(--header-frost-saturation, 1))
    brightness(var(--header-frost-brightness, 1));
  view-transition-name: yk-site-header;
  @media (max-width: 1180px) {
    gap: 26px;
  }
}

/* One restrained frosted-glass sheet on every route. Its flat translucent coat
 * develops with scroll together with blur and colour diffusion; there is still
 * no gradient, displacement, ripple, border or shader layer. */
.site-header::before {
  content: none;
}

.site-brand {
  /* The wordmark is now the mark plus `YK` only — the rule and `Law` were cut
     from the asset rather than hidden, so nothing ships that is not shown.
     Driven by height because the crop changed the aspect from 4.32 to 2.48; the
     old width rule would have made it 60px tall inside the header. */
  display: flex;
  align-items: center;
  height: 46px;
}

.site-brand img {
  width: auto;
  height: 100%;
  display: block;
}

.primary-navigation {
  justify-self: end;
  height: 100%;
}

.primary-menu {
  height: 100%;
  display: flex;
  gap: clamp(26px, 2.5vw, 48px);
  align-items: center;
  list-style: none;
  @media (max-width: 1180px) {
    gap: clamp(26px, 2.9vw, 48px);
  }
}

.primary-menu > li {
  height: 100%;
  display: flex;
  align-items: center;
}

.primary-menu > li > a {
  position: relative;
  padding: 8px 0;
  font-size: 14.5px;
  font-weight: 600;
  letter-spacing: 0.012em;
}

.primary-menu > li > a::after {
  content: "";
  position: absolute;
  inset: auto 0 0;
  height: 1px;
  background: var(--gold);
  transform: scaleX(0);
  transform-origin: right;
  transition: transform 360ms cubic-bezier(0.22, 1, 0.36, 1);
}

.primary-menu > li:hover > a::after,
.primary-menu > li:focus-within > a::after {
  transform: scaleX(1);
  transform-origin: left;
}

.primary-menu > li > a span {
  display: inline-block;
  margin-left: 2px;
  color: var(--gold);
  transition: transform 300ms ease;
}
.header-search {
  width: 38px;
  height: 38px;
  padding: 7px;
  border: 0;
  background: transparent;
  cursor: pointer;
}

.header-search svg {
  fill: none;
  stroke: var(--ink);
  stroke-width: 1.4;
  transition: transform 320ms cubic-bezier(0.22, 1, 0.36, 1);
}

.header-search:hover svg {
  transform: rotate(-8deg) scale(1.08);
}

.menu-toggle {
  display: none;
}

/* Was `place-items: center` over three stacked children — form, status, results.
   The three tracks resolved to 213/36/399px at 1440 while the results box asked
   for 460px, and a centred item overflows in both directions, so 61px of results
   printed straight over the "6 RESULTS" line. Every laptop-class window height
   showed the collision.
   An explicit row template fixes the order and gives the results the leftover
   height instead of a guessed 56vh: `minmax(0, 1fr)` lets the track shrink, so
   the panel can never be taller than the space it is in. */
.search-overlay {
  --search-measure: min(100%, 860px);
  position: fixed;
  z-index: 200;
  inset: 0;
  padding: 14vh max(var(--gutter-min), calc((100vw - 1100px) / 2));
  display: grid;
  grid-template-rows: auto auto minmax(0, 1fr);
  align-content: start;
  justify-items: center;
  visibility: hidden;
  opacity: 0;
  background: rgba(24, 25, 23, 0.97);
  color: #fff;
  transition: visibility 0s linear 400ms, opacity 400ms ease;
}

.search-overlay.is-open {
  visibility: visible;
  opacity: 1;
  transition-delay: 0s;
}

/* The UA's own clear affordance — a stock light-blue × inside the field, next to
   this route's gold SEARCH label and duplicating the overlay's own close. */
.search-overlay input[type="search"]::-webkit-search-cancel-button {
  -webkit-appearance: none;
  appearance: none;
}

/* Sized and placed to land on the magnifier it replaces: same 38px box, same
   gutter expression as the header, so the control does not jump when the overlay
   opens. It was 28px low and 9px left of it. */
.search-close {
  width: 38px;
  height: 38px;
  display: grid;
  place-items: center;
  position: absolute;
  top: calc((var(--header-height) - 38px) / 2);
  right: max(var(--gutter-min), calc((100vw - var(--header-rail)) / 2));
  border: 0;
  background: transparent;
  color: #fff;
  cursor: pointer;
  font-family: var(--serif);
  font-size: clamp(21px, 1.77083vw, 34px);
  font-weight: 200;
  line-height: 1;
  @media (max-width: 1180px) {
    font-size: 34px;
  }
}

/* The form was 1000px and the results 760px, each centred independently inside
   an 1100px column — so the label, the field and its rule started 120px outside
   the results they belong to. Four edges in a layout whose only structure is
   alignment. All three now share one measure. */
.search-overlay form {
  width: var(--search-measure);
}

.search-overlay label {
  display: block;
  margin-bottom: 32px;
  font-family: var(--serif);
  font-size: clamp(42px, 4.47917vw, 86px);
  letter-spacing: -0.04em;
  @media (max-width: 1180px) {
    font-size: clamp(42px, 6vw, 86px);
  }
}

.search-overlay form > div {
  display: grid;
  grid-template-columns: 1fr auto;
  border-bottom: 1px solid rgba(255, 255, 255, 0.45);
}

.search-overlay input,
.search-overlay form button {
  padding: 18px 0;
  border: 0;
  color: #fff;
  background: transparent;
}

.search-overlay input {
  min-width: 0;
  outline: 0;
  font-size: clamp(15px, 1.04167vw, 20px);
  @media (max-width: 1180px) {
    font-size: 20px;
  }
}

.search-overlay input::placeholder {
  color: rgba(255, 255, 255, 0.35);
}

.search-overlay form button {
  padding-left: 30px;
  cursor: pointer;
  color: #d8ba80;
  font-size: clamp(11px, 0.6548vw, 19.8px);
  font-weight: 700;
  letter-spacing: 0.14em;
  text-transform: uppercase;
}

.hero {
  /* THE FLOOR IS 620, NOT 820. The hero's own content — the strategy line, the
     quotation and the support block that carries "How can we help?" — measures
     328 to 366px at every width. The 820 floor was never about fitting that; it
     was a compositional minimum for the artwork, and on any window shorter than
     820 it forced the section past the bottom of the screen and took the
     launcher with it. Measured at 1440x720 before the change: the section was
     820 in a 720 window and "How can we help?" ended 41px BELOW the fold.

     620 is the content at its tallest plus the top padding's floor plus the
     bottom padding — the point below which the composition genuinely cannot
     hold, which is the client's own exception: 除非是在一页放不下了. Above it
     the hero is exactly one screen, whatever the screen is. */
  min-height: max(620px, 100svh);
  position: relative;
  overflow: hidden;
  background: #eee8de url("assets/measured-tension.jpg") 54% center / cover no-repeat;
}

/* The painting ran to the hero's bottom edge and was then cut by `overflow:
   hidden` — a 130-level tonal jump across the full width, straight through the
   most saturated part of the picture, with the news grid's flat paper starting on
   the next row. Every other route on the site ends its artwork with a `__settle`
   ramp; the homepage, which has the largest artwork of all of them, had none.
   z-index 2 puts it over the art and the canvas (both 1) and under `.hero-inner`
   (3), so it settles the picture without touching the type. */
.hero::after {
  content: "";
  position: absolute;
  z-index: 2;
  inset: auto 0 0;
  /* Still compact, but with enough intermediate opacity steps that the painting
     settles into the paper instead of changing tone in one visible band. */
  height: clamp(68px, 8vh, 104px);
  pointer-events: none;
  background: linear-gradient(180deg,
    rgba(242, 238, 230, 0) 0%,
    rgba(242, 238, 230, 0.05) 18%,
    rgba(242, 238, 230, 0.14) 36%,
    rgba(242, 238, 230, 0.3) 54%,
    rgba(242, 238, 230, 0.52) 70%,
    rgba(242, 238, 230, 0.76) 84%,
    var(--paper) 100%);
}

.hero-art,
.hero-canvas,
.hero-reading-field {
  position: absolute;
  inset: 0;
}

.hero-art {
  z-index: 1;
  opacity: 1;
  mix-blend-mode: normal;
  background: url("assets/measured-tension.jpg") 54% center / cover no-repeat;
  transform: scale(1.025);
  transition: opacity 900ms cubic-bezier(0.22, 1, 0.36, 1);
  will-change: transform;
}

.hero-art::after {
  content: "";
  position: absolute;
  inset: 0;
  opacity: 0.14;
  mix-blend-mode: soft-light;
  background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 180 180' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.9' numOctaves='3' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)' opacity='.45'/%3E%3C/svg%3E");
}

.hero-canvas {
  z-index: 1;
  width: 100%;
  height: 100%;
  display: block;
  pointer-events: none;
  opacity: 0;
  transition: opacity 900ms cubic-bezier(0.22, 1, 0.36, 1);
  will-change: opacity;
}

.hero-canvas.is-ready {
  opacity: 1;
}

.hero.has-generative-art .hero-art {
  opacity: 0;
}

/* The reading field, retuned to the composition it now has to serve.
 *
 * This ramp is the site's own device — every other route lifts the left of its artwork
 * the same way — and it was already here. It simply released too early for the
 * quotation's new width: 0.12 by 65%, while the type now runs to 66.7%. Measured across
 * eighteen screens, the ground under the tail came out at rgb(107, 87, 111) and similar,
 * where the quotation's ink holds 1.86 to 2.45:1 — under the 3:1 large text needs, on
 * eleven of the eighteen.
 *
 * The stops are derived rather than dialled. Compositing paper over that ground at alpha
 * a gives bg*(1-a) + paper*a; at a = 0.55 the result is rgb(185, 158, 180), luminance
 * 0.379, and 4.6:1 against the ink. So the ramp holds ~0.55 through the two-thirds mark
 * and releases after it, which is the same line the composition draws: type on the lifted
 * left two thirds, the painting at full strength in the right third. The falloff is spread
 * over a fifth of the width so it has no edge — the one thing two earlier attempts at a
 * wash got wrong.
 *
 * The faint darkening at the far right is kept: it is what stops the painting's brightest
 * corner from competing with the type. */
.hero-reading-field {
  z-index: 2;
  background:
    linear-gradient(
      90deg,
      rgba(248, 244, 236, 0.94) 0%,
      rgba(248, 244, 236, 0.88) 30%,
      rgba(248, 244, 236, 0.76) 50%,
      rgba(248, 244, 236, 0.62) 62%,
      rgba(248, 244, 236, 0.55) 68%,
      rgba(248, 244, 236, 0.3) 75%,
      rgba(248, 244, 236, 0.09) 83%,
      rgba(248, 244, 236, 0) 90%,
      rgba(20, 15, 22, 0.08) 100%
    ),
    linear-gradient(180deg, rgba(248, 244, 236, 0.15), transparent 62%, rgba(19, 15, 20, 0.15));
}

/* The hero quote in the markup is a fallback, not the thing that gets shown.
   `hero-wisdom.js` picks a random maxim, splits it into glyphs clipped to zero and
   burns it in — but it runs at the end of the body, so the markup's placeholder had
   already painted at full opacity. Measured on the deployed site with a CDP
   screencast: the placeholder fully legible at 150ms, blank at 253ms, and a
   *different* quote finishing its arrival at 1300ms. That is the flash the client
   reported.
   Hidden only when scripting is present — `.js` is set by an inline script in the
   head, before first paint — and only until the script marks itself ready, so a
   visitor without JS still gets the static quote and a script that bails still
   reveals it. `visibility`, not `opacity`: the burn drives opacity itself, and the
   canvas needs the glyphs to stay measurable. */
.js .hero-wisdom:not([data-wisdom-ready]) .hero-quote__visual,
.js .hero-wisdom:not([data-wisdom-ready]) .hero-quote__lettering,
.js .hero-wisdom:not([data-wisdom-ready]) .hero-quote__by {
  visibility: hidden;
}

/* The hero is a column of three: the strategy line holds the top anchor under
 * the masthead, the support block holds the foot, and the quotation between
 * them takes every remaining pixel through auto margins and splits it in half.
 * That last part is what keeps the white above the quotation and the white
 * below it equal without either number being written down — see .hero-wisdom.
 * The quotation used to be positioned absolutely at half the window height,
 * which is a different point entirely and measured 30–90px off. */
.hero-inner {
  /* THE ONE GAP, WRITTEN ONCE AND SPENT ON BOTH SIDES. The client asked for the
     white above the quotation and the white below it to be the same: 「它下面
     （也就是到 Australia legal）和上面（到 legal strategy）这两块的空白是一样的」.
     Two numbers that have to stay equal are a number that will not — so there is
     one, and the strategy line's bottom margin and the support block's top
     padding both read it. It is a FLOOR, not the gap: on any screen with room to
     spare the auto margins on .hero-wisdom below add the same amount to each
     side, so what a visitor actually sees is floor + half the free space, twice.
     It only becomes the visible gap on a window too short for the free space to
     exist, which is exactly when a minimum is what you want. */
  --hero-band-gap: clamp(42px, 5.4vh, 62px);
  position: relative;
  z-index: 3;
  width: var(--page);
  min-height: max(620px, 100svh);
  margin: 0 auto;
  /* The top padding's FLOOR comes down with it. 152px was the binding constraint
     on a short window — 17vh only reaches it at 894px tall — so the padding, not
     the content, was what would not fit. 116 still clears the fixed masthead
     with room to spare. */
  padding: clamp(116px, 17vh, 180px) 0 clamp(36px, 3.02083vw, 58px);
  display: flex;
  flex-direction: column;
  @media (max-width: 1180px) {
    padding: clamp(152px, 17vh, 180px) 0 58px;
  }
}

.hero h1 {
  max-width: clamp(510px, 43.2292vw, 830px);
  margin: 0;
  font-family: var(--serif);
  font-size: clamp(68px, 5.36458vw, 103px);
  font-weight: 400;
  letter-spacing: -0.053em;
  line-height: 0.98;
  @media (max-width: 1180px) {
    max-width: 830px;
    font-size: clamp(68px, 6.7vw, 103px);
  }
}

.hero-title-line {
  display: block;
  white-space: nowrap;
}

.hero-title-char {
  display: inline-block;
}

.hero-title-space {
  width: 0.24em;
  display: inline-block;
}

.hero-title-reveal .hero-title-char {
  opacity: 0;
  filter: blur(7px);
  transform: translate3d(0, 36px, 0);
  will-change: transform, opacity, filter;
}

.hero-strategy-line {
  /* The floor under the quotation's top gap. It was clamp(28px, 21vh, 210px)
     and it was decorative: with the quotation positioned absolutely, this
     margin decided nothing a visitor could see, because the support block
     below took every remaining pixel through `margin-top: auto` whatever this
     number was. Now it is half of a matched pair — see --hero-band-gap. */
  margin: 0 0 var(--hero-band-gap);
  color: #675641;
  /* Raised from clamp(11px, 0.6548vw, 19.8px) at the client's direction — "放大
     一点点". One step up the same ramp: 13 at the floor, 23.4 at the ceiling,
     and the vw coefficient stays proportional to the authored size the way the
     note at the head of this file requires. */
  font-size: clamp(13px, 0.7738vw, 23.4px);
  font-weight: 700;
  letter-spacing: 0.16em;
  line-height: 1.25;
  text-transform: uppercase;
}

.hero-wisdom {
  /* EQUAL WHITE ABOVE AND BELOW, BY CONSTRUCTION RATHER THAN BY ARITHMETIC.
   *
   * This group used to be `position: absolute; top: 50svh` — centred in the
   * window, which is not the same thing as centred between the line above it
   * and the block below it, and measured it was not close: at 1440x900 the gap
   * above read 199px against 170px below, and on a phone 223 against 133.
   * Half the window is only the midpoint of the two blocks if the masthead
   * clearance above happens to equal the launcher stack below, and it never
   * does.
   *
   * `margin-block: auto` on the one in-flow item that has it is what makes the
   * two gaps identical without measuring anything: the flex column hands ALL of
   * its free space to auto margins, and one item with two of them splits it in
   * half. Both anchors the absolute positioning was protecting survive — the
   * strategy line still sits under the masthead clearance, and the support
   * block is still driven to the foot, now by this item's bottom margin instead
   * of its own `margin-top: auto`.
   *
   * It also holds as the quotation rotates. A longer quote grows this box, the
   * free space shrinks, and both halves shrink by the same amount — so the
   * balance is a property of the layout rather than a number that was true for
   * the sentence that happened to be on screen when it was tuned.
   *
   * `position: relative` stays because hero-wisdom.js positions the burn canvas
   * against this box (see rebuildLayout). Absolute offsets are resolved against
   * the padding box, so the optical padding below does not move it. */
  position: relative;
  margin-block: auto;
  /* NO OPTICAL COMPENSATION HERE, and it was measured rather than assumed. The
   * quotation's line box carries a 0.22em descender guard below the last
   * baseline against 0.08em above the first, which reads like an imbalance the
   * boxes cannot see — but the gap below is drawn from the type to the SUPPORT
   * HEADING, and that block's own top padding sits inside its box and inside
   * that gap. Measured at 1440x900 with the boxes balanced: 17.0px of leading
   * and guard above the glyphs, 15.4px below. A compensation was written here,
   * it was 20px, and it made the gaps 22px unequal in the other direction. */
  width: 100%;
  max-width: min(1080px, 100%);
  isolation: isolate;
}

/* The ground under the quotation, and why it is a halo rather than a wash.
 *
 * The painting behind the hero runs from cream on the left to a mid purple on the right,
 * and a long quotation reaches into that purple — measured, rgb(107, 84, 109) under the
 * tail. Nothing mid-toned survives there: the near-black this line used to be held
 * 2.53:1, already under the 3:1 large text needs, and a lighter ink measures 1.6.
 *
 * Two attempts at lifting the ground with a background wash are worth recording, because
 * both failed the same way and the second failure is what names the rule. Inset a tenth
 * with a 115% radius, the gradient still carried 0.88 alpha where the box ended and
 * appeared as a pale panel with three hard edges. Stretched to -80% so it could fade out
 * on its own, it became a band across the whole hero with a visible top and bottom.
 * A wash large enough to cover the type and soft enough to have no edge will always
 * lighten more of the painting than the type occupies. That is not a tuning problem.
 *
 * So the lift travels with the glyphs instead. Two shadows of the page's own paper —
 * one tight, one wide — raise the ground in the millimetre around each letter and
 * nowhere else. Over the cream two thirds it is invisible; over the purple it is what
 * makes the line readable. It also costs nothing when the quotation rotates to a short
 * one that never reaches the dark. */
.hero h1.hero-quote,
.hero-quote__zh {
  /* Named so the glyph rule below can restate it. A glyph that sets its own
     text-shadow REPLACES this rather than adding to it, and this is what makes
     the line readable over the painting's dark side — so the lit glyph has to
     carry both, and there must be exactly one copy of these four layers. */
  --quote-paper-halo:
    0 0 7px rgba(246, 243, 236, 1),
    0 0 18px rgba(246, 243, 236, 0.96),
    0 0 46px rgba(246, 243, 236, 0.74),
    0 0 96px rgba(246, 243, 236, 0.5);
  text-shadow: var(--quote-paper-halo);
}

/* THE CURSOR MOVES THE LETTERS, AND NOTHING ELSE ABOUT THEM CHANGES.
 *
 * There was a spotlight here — two warm layers on top of the paper halo, driven by
 * a `--lit` number per glyph — and the client has withdrawn it: 不要聚光灯了. The
 * glow, the `--lit` custom property and the ink shift that went with it are gone
 * rather than switched off. What answers the cursor now is a faint upward
 * repulsion, written as a transform in hero-wisdom.js; the paper halo the glyphs
 * inherit from `.hero-quote` is once again the only thing behind them.
 *
 * The three declarations below are what makes that transform possible at all: a
 * transform does not apply to a non-replaced inline element, so each glyph is an
 * inline-block, and the identity transform gives the compositor something to
 * promote before the first frame of movement. */

.hero-wisdom > .hero-quote,
.hero-wisdom > .hero-quote__zh,
.hero-wisdom > .hero-quote__by {
  position: relative;
  z-index: 1;
}

.hero-wisdom__burn-layer {
  position: absolute;
  z-index: 2;
  display: block;
  pointer-events: none;
  opacity: 1;
  transform: translateZ(0);
}

.hero-wisdom__burn-layer[hidden] {
  display: none;
}

/* Colour comes from --quote-ink at :root, which is also where hero-wisdom.js reads it.
   This declaration is what a visitor sees before the engine starts and if it never
   does; from the first frame onward the engine writes the same value inline. */
/* 1080px is the fallback below 768, where the two-thirds rule is lifted; above it the
   media query further down takes over. */
.hero h1.hero-quote {
  max-width: clamp(664px, 56.25vw, 1080px);
  color: var(--quote-ink);
  font-size: clamp(44px, 3.54167vw, 68px);
  letter-spacing: -0.04em;
  /*
   * The quotation uses an editorial serif with generous descenders.  A tight
   * headline line-height lets a second line collide with glyphs such as g, y
   * and p while the words are moving.  Keep deliberate breathing room in the
   * line box as well as below the final baseline, rather than masking it.
   */
  /*
   * This is intentionally more generous than a conventional display heading:
   * it is a live, translated word field rather than static type.  The extra
   * baseline distance and lower guard band ensure descenders remain intact
   * even while a word is settling through its final few pixels of motion.
   */
  padding: 0.08em 0.025em 0.22em;
  line-height: 1.2;
  @media (max-width: 1180px) {
    max-width: 1080px;
    font-size: clamp(44px, 4.5vw, 68px);
  }
}

/* The length classes no longer change the quotation's size above 680px, and the reason
   is worth keeping: they used to set it *upward* — base 68px, `--long` 80px,
   `--very-long` 73px — so the quotations with the most words to fit were given the least
   room per word. That only worked because the measure was free to run on into the
   painting. With the measure fixed at two thirds, one size holds every one of the ten
   quotations to two lines at every width from 768 up; measured, all ninety
   combinations. A second size would be a number to keep in step for no gain.
   Below 680 the mobile rules still differentiate — there the measure is the full column
   and length is the only thing left to respond to. */

/* The two-thirds composition, and where it stops.
 *
 * The painting behind the hero runs cream to a mid purple, and the purple lives in the
 * right third. Type crossing into it was this page's oldest legibility problem:
 * measured, the line ended anywhere between x=742 and x=1066 at 1440, and under the tail
 * the ground is about rgb(107, 84, 109), where even the near-black this line used to be
 * held 2.53:1 against the 3:1 large text needs. Two attempts at lifting that ground with
 * a wash both read as a panel. Keeping the line out of the third leaves the artwork
 * alone.
 *
 * Two thirds of the *window*, not of the container: the painting is sized to the window,
 * so its purple sits at a fixed fraction of the window whatever the container does. The
 * container is centred, so the distance from the window's left edge to the type is
 * (100vw - --page) / 2, and the measure is what is left of 66.67vw after it. One
 * expression covers both of --page's regimes.
 *
 * It starts at 768 because below that it stops being a composition and becomes a
 * squeeze: at 700 the measure is 427px, and four of the ten quotations need three lines
 * to fit it. A phone has no room for a two-thirds composition and its crop of the
 * painting is a different picture anyway. */
@media (min-width: 768px) {
  .hero h1.hero-quote {
    max-width: calc(66.67vw - (100vw - var(--page)) / 2);
  }
}

/* A MINIMUM GAP, NOT A POSITION — and now a single one rather than a pair.
   These were two rules, a smaller bottom margin on the strategy line and a
   smaller top padding on the support block, so a long quotation tightened the
   two gaps by DIFFERENT amounts: 150px against 46px at the ceiling. That is the
   asymmetry the client saw, arriving or not arriving with whichever quotation
   the rotation happened to pick. One floor, tightened once, keeps the two sides
   equal in the only regime where a floor is visible at all. */
.hero.hero-wisdom--long .hero-inner {
  --hero-band-gap: clamp(30px, 4vh, 46px);
}

.hero-quote__visual,
.hero-quote__lettering {
  display: block;
  overflow: visible;
}

.hero-quote__burn-word {
  margin-right: 0.23em;
  display: inline-block;
  white-space: nowrap;
}

.hero-quote__burn-glyph {
  display: inline-block;
  transform: translate3d(0, 0, 0);
  will-change: transform;
}

.hero-quote__burn-glyph--zh {
  display: inline-block;
}

.hero-quote__burn-zh {
  overflow: visible;
}

.hero-quote__zh {
  max-width: clamp(467px, 39.5833vw, 760px);
  margin: 23px 0 0;
  color: var(--quote-ink-zh);
  font-family: var(--serif);
  font-size: clamp(18px, 1.19792vw, 23px);
  font-weight: 400;
  letter-spacing: 0.045em;
  line-height: 1.22;
  @media (max-width: 1180px) {
    max-width: 760px;
    font-size: clamp(18px, 1.45vw, 23px);
  }
}

.hero-quote__by {
  display: block;
  margin-top: 16px;
  color: #746f66;
  font-size: clamp(10px, 0.5952vw, 18px);
  font-style: normal;
  font-weight: 700;
  letter-spacing: 0.15em;
  line-height: 1.22;
  text-transform: uppercase;
}

.hero.hero-burn-enhanced .hero-quote__by {
  opacity: 0;
  will-change: transform, opacity;
}

.hero-line {
  display: block;
  width: max-content;
  max-width: 100%;
}

.hero-line.on-art,
.hero-line.on-art + .hero-line {
  color: var(--ink);
  text-shadow: none;
}

.hero-line em {
  color: #9a573e;
  font-weight: 400;
}

.hero-support {
  width: min(720px, 64vw);
  /* NO `margin-top: auto` HERE ANY MORE, and its absence is what makes the two
     gaps equal. It is still driven to the foot of the hero — but by the auto
     margins on .hero-wisdom, which take all of the free space. A third auto
     margin on this block would have split that space three ways instead of two
     and lifted the block off the bottom. The floor below is the other half of
     the matched pair; see --hero-band-gap on .hero-inner. */
  padding-top: var(--hero-band-gap);
  display: grid;
  grid-template-columns: 1fr;
  gap: clamp(20px, 1.66667vw, 32px);
  @media (max-width: 1180px) {
    gap: 32px;
  }
}

.hero-support h2 {
  max-width: clamp(399px, 33.8542vw, 650px);
  margin: 0;
  color: #484842;
  font-family: var(--serif);
  font-size: clamp(20px, 1.45833vw, 28px);
  font-weight: 400;
  letter-spacing: -0.015em;
  line-height: 1.26;
  @media (max-width: 1180px) {
    max-width: 650px;
    font-size: clamp(20px, 1.8vw, 28px);
  }
}

.hero-ask-launch {
  width: min(100%, 560px);
  padding: 15px 0;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: clamp(15px, 1.25vw, 24px);
  border: 0;
  border-top: 1px solid var(--ink);
  border-bottom: 1px solid var(--ink);
  color: var(--ink);
  background: transparent;
  cursor: pointer;
  text-align: left;
  transition: padding 320ms cubic-bezier(0.22, 1, 0.36, 1), color 220ms ease;
  @media (max-width: 1180px) {
    gap: 24px;
  }
}

.hero-ask-launch__copy {
  min-width: 0;
  display: grid;
  gap: 4px;
}

.hero-ask-launch__eyebrow {
  color: var(--gold);
  font-size: clamp(10px, 0.5952vw, 18px);
  font-weight: 700;
  letter-spacing: 0.15em;
  text-transform: uppercase;
}

.hero-ask-launch__prompt {
  font-family: var(--serif);
  font-size: 19px;
  letter-spacing: -0.01em;
}

.hero-ask-launch__arrow,
.link-arrow {
  display: inline-block;
  color: var(--gold);
  fill: none;
  stroke: currentColor;
  stroke-width: 1.6;
  stroke-linecap: square;
  stroke-linejoin: miter;
  transition: transform 350ms cubic-bezier(0.22, 1, 0.36, 1);
}

.hero-ask-launch__arrow {
  width: 20px;
  height: 20px;
  flex: 0 0 20px;
}

.link-arrow {
  width: 17px;
  height: 17px;
  margin-left: 4px;
  vertical-align: -0.16em;
}

.hero-ask-launch:hover,
.hero-ask-launch:focus-visible {
  padding-inline: 8px;
  color: #7d4634;
}

.hero-ask-launch:hover .hero-ask-launch__arrow,
.hero-ask-launch:focus-visible .hero-ask-launch__arrow,
.news-card:hover .link-arrow,
.section-link:hover .link-arrow,
.network-intro > a:hover .link-arrow {
  transform: translate(4px, -4px);
}

/*
 * Quiet-settle motion baseline
 *
 * Generic components are never displaced, clipped, blurred or swept into the
 * page. JavaScript develops only the final few percent of their existing
 * opacity. This class makes that stationary contract explicit and prevents an
 * old mask/clip declaration from returning through stale cached styles.
 */
.quiet-reveal-target {
  transform: none;
  clip-path: none;
  -webkit-mask-image: none;
  mask-image: none;
}

.news-stream {
  padding: 38px var(--band-inset) clamp(71px, 5.98958vw, 115px);
  background: var(--paper);
  @media (max-width: 1180px) {
    padding: 38px var(--band-inset) 115px;
  }
}

/* THE COLUMN COUNT FOLLOWS THE CARD CONTAINER, NOT A DEVICE NAME.
 *
 * `auto-fit` remains the decision-maker. Its minimum card width now scales
 * from 220px through the tablet range to the established 370px desktop floor:
 * the fluid reading band can therefore hold two deliberately narrow cards on an
 * iPad, two wider cards on a laptop, and three cards only when the wide band
 * genuinely has room. `min(100%, ...)` keeps the intrinsic minimum from ever
 * widening a one-column container. The 680px rule below still makes the phone
 * contract explicit, while the side insets remain completely independent. */
/* SIX CARDS, THREE ACROSS, TWO ROWS — and the count is stated, not inferred.
 *
 * This was `auto-fit` with a `minmax` floor of clamp(220px, 28vw, 370px). At
 * 1440 that floor computes to 403px inside a band of about 941, so auto-fit
 * could only ever fit two, and the client saw two very wide cards where they
 * expected three. Lowering the floor until three happen to fit would have made
 * the count a side effect of arithmetic that changes again at the next screen
 * size: at 2560 the same floor lets four in, and six cards in four columns is
 * 4 + 2.
 *
 * So the desktop grid says three. Below 1181 the floor still decides, because
 * that is where the number genuinely has to fall to two and then to one, and
 * the 680px rule further down still takes it to a single column. */
.news-grid {
  display: grid;
  grid-template-columns: repeat(
    auto-fit,
    minmax(min(100%, clamp(220px, 28vw, 370px)), 1fr)
  );
  border-top: 1px solid var(--ink);
  border-left: 1px solid var(--line);
  @media (min-width: 1181px) {
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }
}

/* 21px against a visible border, on a page whose other bordered containers use
   38px. The cards were the tightest boxes on the site and the likeliest thing the
   client meant by elements sitting on their own edges. */
.news-card {
  min-height: clamp(278px, 23.5417vw, 452px);
  position: relative;
  padding: 30px 30px 32px;
  display: flex;
  flex-direction: column;
  border-right: 1px solid var(--line);
  border-bottom: 1px solid var(--line);
  transition:
    background-color 400ms ease,
    color 400ms ease;
  @media (max-width: 1180px) {
    /* Match the compact card immediately above this breakpoint. A later
       590px override used to replace this value between 961px and 1180px,
       leaving roughly 200px between the summary and READ MORE; one pixel
       wider, the same card collapsed back to its content height. */
    min-height: 452px;
  }
}

.news-visual {
  height: clamp(93px, 7.91667vw, 152px);
  margin: -21px -21px 21px;
  display: block;
  overflow: hidden;
  background: #d8d1c4;
  @media (max-width: 1180px) {
    height: 152px;
  }
  /* THE HEIGHT FOLLOWS THE CARD, NOT THE VIEWPORT — 2026-08-08, with the band.

     The clamp above sizes the picture from the VIEWPORT, which was fine while
     the card was pinned near 440px whatever the screen. Raising --band to
     1460 untied the card, and a fixed height then turns the photograph into a
     strip: at 2560 the card is 730 and the image was still 152 tall, a ratio
     of 4.7 against the 3.6 it is drawn at.

     3.62 is not a chosen number. It is the ratio this image already has at
     1440 — the width the cards were drawn and signed off at — so between 1181
     and about 1467, where the card has not grown, this rule reproduces the
     clamp's heights to within a pixel (1200: 94 against 95; 1440: 114 against
     114). It only starts doing anything where the card is genuinely wider
     than it used to be, which is the only place there was a problem. */
  @media (min-width: 1181px) {
    height: auto;
    aspect-ratio: 3.62;
  }
}

.news-visual img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  filter: saturate(0.78) contrast(0.94);
  transform: scale(1.002);
  transition:
    filter 650ms ease,
    transform 900ms cubic-bezier(0.22, 1, 0.36, 1);
}

.news-card:hover .news-visual img {
  filter: saturate(0.95) contrast(1);
  transform: scale(1.055);
}

.news-card::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 0;
  opacity: 0;
  background: var(--ink);
  transform: scaleY(0);
  transform-origin: bottom;
  transition:
    opacity 450ms ease,
    transform 550ms cubic-bezier(0.22, 1, 0.36, 1);
}

.news-card > * {
  position: relative;
  z-index: 1;
}

.news-card:hover {
  color: #f8f4ec;
}

.news-card:hover::before {
  opacity: 1;
  transform: scaleY(1);
}

.news-meta {
  display: flex;
  justify-content: space-between;
  gap: 20px;
  padding-bottom: 14px;
  border-bottom: 1px solid currentColor;
  color: var(--gold);
  font-size: clamp(10px, 0.5952vw, 18px);
  font-weight: 700;
  letter-spacing: 0.14em;
  text-transform: uppercase;
}

.news-meta time {
  color: var(--muted);
  font-weight: 600;
}

.news-card:hover .news-meta time,
.news-card:hover > p {
  color: rgba(255, 255, 255, 0.63);
}

.news-card h2 {
  margin: 24px 0 0;
  font-family: var(--serif);
  font-size: clamp(22px, 1.51042vw, 29px);
  font-weight: 400;
  letter-spacing: -0.025em;
  line-height: 1.12;
  @media (max-width: 1180px) {
    font-size: clamp(22px, 1.75vw, 29px);
  }
}

.news-card > p {
  margin: 20px 0 0;
  color: var(--muted);
  font-size: 13px;
  line-height: 1.15;
  transition: color 400ms ease;
}

.text-link {
  margin-top: auto;
  padding-top: 24px;
  display: flex;
  justify-content: space-between;
  align-items: center;
  font-size: clamp(10px, 0.5952vw, 18px);
  font-weight: 700;
  letter-spacing: 0.14em;
  text-transform: uppercase;
}

.text-link .link-arrow {
  width: 21px;
  height: 21px;
  flex: 0 0 21px;
  margin-left: 18px;
  vertical-align: baseline;
}

.news-card:hover .text-link .link-arrow {
  color: #f5f0e7;
  transform: translate(4px, -4px);
}

.about-section,
.expertise-section,
.awards-section {
  padding: clamp(64px, 5vw, 96px) var(--band-inset);
  /* Expertise alone tightens — the client asked for that section to be more
     compact, and Awards below it was not part of that. */
  &.expertise-section {
    padding: clamp(48px, 3.75vw, 72px) var(--band-inset);
  }
  @media (max-width: 1180px) {
    /* THE NARROW BANDS WERE PINNED TO THE CLAMP'S CEILING, which is the opposite
     of what a narrow screen needs: `clamp(64px, 5vw, 96px)` resolves to 64px at
     1181px, and this override then handed 96px to everything below — a 390px
     phone was getting half again the air a 1440px desktop gets, 95px above and
     95px below every section. Measured 2026-08-09: 760px of the homepage's
     11,390px on a phone was section padding alone.
     Scaling instead, and landing on the band above's 64px at the breakpoint so
     nothing jumps as the window crosses it. */
    padding: clamp(44px, 5.4vw, 64px) var(--band-inset);
    &.expertise-section {
      padding: clamp(34px, 4.1vw, 48px) var(--band-inset);
    }
  }
}

/* THE RECOGNITIONS BAND, ONCE THE TABLE UNDER IT WENT.
 *
 * Its one sentence was left in `.section-heading`, which is a heading treatment:
 * a rule spanning the full measure with the words at the left of it. Measured on
 * the deploy, the rule ran 556px past the end of the sentence and 73% of the
 * 195px band was empty padding sized for three columns that no longer exist. A
 * rule under a heading is a promise that something follows, and nothing did. The
 * client's word for it was 丑.
 *
 * So it stops being a heading and becomes a statement — the same move the footer
 * makes, and the footer's own note is the reason this is not bigger: "at 62px
 * this was a billboard with a page underneath it; the sentence is the firm's
 * voice, not its masthead". 20ch is what breaks it into two lines, and
 * `text-wrap: balance` is what makes them even rather than leaving one word
 * stranded. No rule, no eyebrow: the sentence is the whole content, so anything
 * else in the band would be furniture around an empty room.
 *
 * The padding comes down with it — the band was proportioned for a grid. 150px
 * against 195px, and better than half of it is now ink. */
.awards-section.awards-section--statement {
  padding: clamp(34px, 2.5vw, 48px) var(--band-inset);
  @media (max-width: 1180px) {
    padding: clamp(30px, 3.4vw, 40px) var(--band-inset);
  }
}

.awards-statement {
  max-width: 20ch;
  margin: 0;
  color: var(--ink);
  font-family: var(--serif);
  font-size: clamp(28px, 2.6vw, 46px);
  font-weight: 400;
  letter-spacing: -0.022em;
  line-height: 1.1;
  text-wrap: balance;
}

.about-section {
  background: var(--paper-bright);
}

.section-heading {
  /* The rule sat 36px under the heading whatever the heading was: 0.47em of a 78px
     title, 0.84em of a 44px one. A fixed gap under fluid type is a gap that changes
     meaning as the type moves, and it read as slack the moment the heading came down.
     Tied to the heading's own scale instead — the same 0.47 at every width. It cannot
     be written in `em`, because `em` here resolves against this flex container's font
     size and not the h2's; the same reason the editorial measure is a plain length. */
  padding-bottom: clamp(14px, 1.36vw, 21px);
  display: flex;
  justify-content: space-between;
  gap: clamp(25px, 2.08333vw, 40px);
  align-items: end;
  border-bottom: 1px solid var(--ink);
  @media (max-width: 1180px) {
    /* Scaled rather than pinned. The value at 1180px is unchanged, so nothing
       moves on a tablet or anywhere wider; it only comes in as the screen
       narrows, which is the direction it should always have gone. */
    gap: clamp(22px, 3.4vw, 40px);
  }
}

/* A section heading is not a page title, and this was set larger than one.
 *
 * The homepage h1 — the rotating quotation, the loudest thing the site says — is
 * clamp(44px, 4.5vw, 68px). This was clamp(48px, 5vw, 78px): a bigger floor, a steeper
 * slope and a bigger cap, so "About YK Law", "Expertise" and "Yingke Awards" were each
 * 72px against an h1 of 64.8px at 1440, and 78 against 68 at 1920. The three section
 * markers outranked the page they sit inside, at every width. That is why the section
 * read as shouting rather than as large: the size was not the problem so much as the
 * size *relative to what is above it*, and there was nothing above it.
 *
 * Now 0.64 of the h1 at every width — floor, slope and cap all scaled by the same
 * figure, so the ratio holds in between and not only at the ends. 42px at 1440 against
 * 64.8, 44 against 68. Still the largest thing in its own section by a factor of 1.5,
 * and clearly answerable to the page title. */
.section-heading h2 {
  margin: 0;
  font-family: var(--serif);
  font-size: clamp(30px, 2.29167vw, 44px);
  font-weight: 400;
  letter-spacing: -0.045em;
  line-height: 0.98;
  @media (max-width: 1180px) {
    font-size: clamp(30px, 2.9vw, 44px);
  }
}

.section-heading h2 span {
  color: var(--muted);
  font-size: 0.56em;
  letter-spacing: -0.02em;
}

.section-link {
  padding-bottom: 5px;
  display: flex;
  gap: 20px;
  align-items: center;
  font-size: 12px;
  font-weight: 700;
  letter-spacing: 0.14em;
  text-transform: uppercase;
}

.about-layout {
  padding-top: clamp(44px, 3.75vw, 72px);
  display: grid;
  grid-template-columns: minmax(250px, 0.62fr) minmax(0, 1.38fr);
  gap: clamp(56px, 5.72917vw, 110px);
  @media (max-width: 1180px) {
    padding-top: 72px;
    gap: clamp(56px, 7vw, 110px);
  }
}

.about-rail {
  position: sticky;
  top: 140px;
  align-self: start;
  width: min(100%, 310px);
  height: max-content;
}

/* THE ABOUT RAIL'S LOGO IS NO LONGER IN THE MARKUP — removed from
   concepts/style-lab/index.html at the client's direction on 2026-08-11, so
   this block and the two under it now match nothing. They are kept rather than
   deleted because the mark is one <div> away from returning and every value
   here was traced from the artwork, not chosen; motion.js's draw is already
   guarded (`if (!mark) return`) and will pick it up again the moment the
   element exists. The same applies to `.about-theme small`, which dressed the
   01/02/03 the client removed in the same pass. */
.about-mark {
  width: min(270px, 92%);
  /* The colour was baked into the PNG this replaced. Kept exactly rather than
     snapped to --gold, because retouching the mark is not a motion change. */
  color: #937452;
}

.about-mark .yk-mark {
  width: 100%;
  height: auto;
  display: block;
  /* The viewBox is the ink's own bounding box, so a stroke centred on the outline
     hangs half a pixel outside it. Without this the drawn line is clipped flat
     along the top of the roundel. */
  overflow: visible;
}

/* Filled is the resting state and the state without JavaScript: the draw is an
   enhancement, so a logo that is never animated is still a logo. motion.js takes it
   apart into a line and puts it back together. */
.about-mark .yk-mark path {
  fill: currentColor;
  stroke: currentColor;
  /* Deliberately not vector-effect: non-scaling-stroke. Chrome scales the dash
     pattern with the element but reports getTotalLength in user units, so a dash
     set to the path's own length fell 5% short and left a fragment of every
     outline painted before the draw had started — 1124 stray pixels, measured,
     and none once this came off. motion.js works out the equivalent width in user
     units from how big the mark actually rendered, which it has to: the mark is
     270px on a desktop and 126px on a phone, so a fixed user-unit width would be
     a clean hairline on one and half a pixel of grey on the other. */
  stroke-width: 0;
}

.about-themes-wrap {
  min-height: clamp(152px, 12.9167vw, 248px);
  position: relative;
  margin: clamp(30px, 2.5vw, 48px) 0 0 12px;
  @media (max-width: 1180px) {
    min-height: 248px;
    margin: 48px 0 0 12px;
  }
}

.about-rail-track,
.about-rail-progress {
  position: absolute;
  left: 6px;
  top: 8px;
  bottom: 8px;
  width: 1px;
  display: block;
  transform-origin: 50% 0;
}

.about-rail-track {
  background: rgba(23, 23, 20, 0.16);
}

.about-rail-progress {
  z-index: 1;
  background: var(--gold);
  transform: scaleY(0);
  will-change: transform;
}

.about-themes {
  position: relative;
  z-index: 2;
  min-height: clamp(152px, 12.9167vw, 248px);
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  list-style: none;
  @media (max-width: 1180px) {
    min-height: 248px;
  }
}

.about-theme {
  min-height: 38px;
  display: grid;
  grid-template-columns: 13px 1fr;
  gap: 20px;
  align-items: start;
  color: #979289;
  /* Raised from clamp(9px, 0.5357vw, 16.2px) — the client asked for this label
     to be bigger, and it was also the smallest type on the home page by some
     way. A 9px floor is under the 12px the screen-matrix audit treats as a
     finding on sight; these three words are now the rail's only content, since
     the numbers above them went, so they carry it. */
  font-size: clamp(13px, 0.7738vw, 23.4px);
  font-weight: 650;
  letter-spacing: 0.075em;
  line-height: 1.15;
  text-transform: uppercase;
  transition: color 450ms cubic-bezier(0.22, 1, 0.36, 1);
}

.about-theme small {
  margin-bottom: 5px;
  display: block;
  color: #aaa49a;
  font-size: 12px;
  font-weight: 700;
  letter-spacing: 0.16em;
  transition: color 450ms cubic-bezier(0.22, 1, 0.36, 1);
}

.about-theme-node {
  width: 13px;
  height: 13px;
  position: relative;
  display: block;
  border: 1px solid rgba(23, 23, 20, 0.22);
  border-radius: 50%;
  background: var(--paper-bright);
  transition:
    border-color 450ms cubic-bezier(0.22, 1, 0.36, 1),
    transform 450ms cubic-bezier(0.22, 1, 0.36, 1);
}

.about-theme-node::after {
  content: "";
  position: absolute;
  inset: 3px;
  border-radius: 50%;
  background: var(--gold);
  transform: scale(0);
  transition: transform 450ms cubic-bezier(0.22, 1, 0.36, 1);
}

.about-theme.is-reached .about-theme-node {
  border-color: rgba(160, 123, 69, 0.64);
}

.about-theme.is-reached .about-theme-node::after {
  transform: scale(0.52);
}

.about-theme.is-active {
  color: var(--ink);
}

.about-theme.is-active small {
  color: var(--gold);
}

.about-theme.is-active .about-theme-node {
  border-color: var(--gold);
  transform: scale(1.08);
}

.about-theme.is-active .about-theme-node::after {
  transform: scale(1);
}

/* 850px of 21px sans is 90 characters a line — the longest measure on the site, in the
   one section that is asking to be read straight through. Derived instead, the way the
   editorial pages are: the average character in this face is 0.45 of the font size, so
   68 characters is 30.2 times it, and the body here is clamp(16px, 1.45vw, 21px).
   Multiplying through gives the line below. */
.about-copy {
  max-width: clamp(483px, 43.8vw, 635px);
}

.about-copy p {
  margin: 0;
  color: #4e4e48;
  font-size: clamp(16px, 1.09375vw, 21px);
  line-height: 1.15;
  @media (max-width: 1180px) {
    font-size: clamp(16px, 1.45vw, 21px);
  }
}

/* The lead. It was clamp(26px, 2.5vw, 38px) — 36px at 1440, against a "| Yingke
   Australia" set at 40px, so the heading's own second half and the paragraph under it
   were 11% apart and read as one level. A lead has to be clearly below the heading and
   clearly above the body; this is 0.64 of the section heading, the same step the
   heading takes from the h1. */
.about-copy p:first-child {
  margin-left: clamp(-72px, -5vw, -48px);
  color: var(--ink);
  font-family: var(--serif);
  font-size: clamp(21px, 1.45833vw, 28px);
  letter-spacing: -0.025em;
  line-height: 1.15;
  @media (max-width: 1180px) {
    font-size: clamp(21px, 1.86vw, 28px);
  }
}

.about-copy p + p {
  margin-top: 32px;
}

/* `.about-copy p:last-child` was here — a gold paragraph under a rule. It has
   matched nothing since d92 moved the figures into this column, because the
   `<dl>` is the last child now and no paragraph is. It is deleted rather than
   left, because it was not merely dead: the in-page editor wraps the run of
   paragraphs in an element of its own so the field it stamps contains exactly
   that field, and inside that wrapper the last paragraph IS the last child. The
   rule would have come back to life in edit mode only, which is the worst place
   for a style to appear. */

.wisdom-demo {
  min-height: clamp(504px, 42.7083vw, 820px);
  position: relative;
  overflow: hidden;
  padding: clamp(43px, 3.64583vw, 70px) max(var(--gutter-min), calc((100vw - 1460px) / 2)) clamp(49px, 4.16667vw, 80px);
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  color: #f8f3e9;
  background: #0d1424;
  isolation: isolate;
  @media (max-width: 1180px) {
    min-height: 820px;
    padding: 70px max(var(--gutter-min), calc((100vw - 1460px) / 2)) 80px;
  }
}

.wisdom-demo::after {
  content: "";
  position: absolute;
  z-index: 1;
  inset: 0;
  pointer-events: none;
  background:
    linear-gradient(180deg, rgba(7, 10, 19, 0.38), transparent 28%, transparent 72%, rgba(7, 10, 19, 0.38)),
    radial-gradient(circle at center, transparent 35%, rgba(7, 10, 19, 0.18));
}

.wisdom-canvas {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  display: block;
}

.wisdom-background {
  z-index: 0;
}

.wisdom-physics {
  display: none;
}

.wisdom-topline,
.quote-stage,
.another-maxim {
  position: relative;
  z-index: 3;
}

.wisdom-topline {
  display: flex;
  justify-content: flex-start;
  padding-bottom: 18px;
  border-bottom: 1px solid rgba(255, 255, 255, 0.22);
}

.section-label {
  margin: 0;
  color: var(--gold);
  font-size: clamp(10px, 0.5952vw, 18px);
  font-weight: 700;
  letter-spacing: 0.19em;
  text-transform: uppercase;
}

.section-label::before {
  content: "";
  display: inline-block;
  width: 23px;
  height: 1px;
  margin: 0 11px 3px 0;
  background: currentColor;
}

.section-label.light {
  color: #d6b981;
}

.quote-stage {
  width: min(1120px, 90%);
  margin: clamp(49px, 4.16667vw, 80px) auto clamp(31px, 2.60417vw, 50px);
  text-align: center;
  @media (max-width: 1180px) {
    margin: 80px auto 50px;
  }
}

.quote-stage blockquote {
  min-height: 2.12em;
  margin: 0;
  display: block;
  font-family: var(--serif);
  font-size: clamp(40px, 4.47917vw, 86px);
  font-weight: 400;
  letter-spacing: -0.035em;
  line-height: 1.03;
  text-wrap: balance;
  opacity: 0;
  transition: opacity 150ms ease;
  @media (max-width: 1180px) {
    font-size: clamp(40px, 6vw, 86px);
  }
}

.quote-lettering {
  display: inline;
}

.quote-word {
  display: inline-block;
  white-space: nowrap;
}

.quote-letter {
  display: inline-block;
  opacity: 0;
  filter: blur(0.8px);
  transform: translateY(2px);
  animation: quote-letter-settle 360ms cubic-bezier(0.22, 1, 0.36, 1) var(--letter-delay, 0ms) both;
  will-change: opacity, filter, transform;
}

.quote-letter--space {
  width: 0.27em;
}

.quote-letter--mark {
  color: #d6b981;
}

@keyframes quote-letter-settle {
  from {
    opacity: 0;
    filter: blur(0.8px);
    transform: translateY(2px);
  }

  to {
    opacity: 1;
    filter: blur(0);
    transform: translateY(0);
  }
}

.wisdom-demo.quote-revealed .quote-stage blockquote,
.wisdom-demo.quote-revealed .quote-stage > p,
.wisdom-demo.quote-revealed .quote-stage cite {
  opacity: 1;
}

.quote-stage > p {
  margin: 18px 0 0;
  color: rgba(255, 255, 255, 0.66);
  font-family: var(--serif);
  font-size: clamp(15px, 1.09375vw, 21px);
  opacity: 0;
  transition: opacity 150ms ease 70ms;
  @media (max-width: 1180px) {
    font-size: 21px;
  }
}

.quote-stage cite {
  display: block;
  margin-top: 38px;
  color: #d6b981;
  font-size: clamp(10px, 0.5952vw, 18px);
  font-style: normal;
  font-weight: 700;
  letter-spacing: 0.19em;
  text-transform: uppercase;
  opacity: 0;
  transition: opacity 180ms ease 760ms;
}

.another-maxim {
  align-self: center;
  padding: 12px 0;
  display: flex;
  gap: 18px;
  align-items: center;
  border: 0;
  border-bottom: 1px solid rgba(255, 255, 255, 0.4);
  color: #fff;
  background: transparent;
  cursor: pointer;
  font-size: clamp(10px, 0.5952vw, 18px);
  font-weight: 700;
  letter-spacing: 0.17em;
  text-transform: uppercase;
}

.another-maxim i {
  color: #d6b981;
  font-size: 17px;
  font-style: normal;
  transition: transform 500ms cubic-bezier(0.22, 1, 0.36, 1);
}

.another-maxim:hover i {
  transform: rotate(-180deg);
}

/* THE DARK BAND IS A MATERIAL, NOT A FILL — 2026-08-11.
 *
 * NO TILE, AND THAT IS THE POINT. This was first a fractal-noise tile blended
 * `overlay`, which on a 0.10-luminance ground did nothing at all — measured, a
 * 120x120 patch varied across four levels out of 255. It was then a set of SVG
 * tiles, and those had a worse fault: the strokes sat ON the tile's edges, so
 * half of every edge stroke was clipped and the halves did not meet when the
 * tile repeated. Measured on the render, columns one tile-period apart differed
 * by up to 8.78 levels on a texture that spans 29 — visible gaps in what is
 * supposed to be a perfect lattice, and the client saw them.
 *
 * `repeating-linear-gradient` has no tile. It is continuous by construction, at
 * any width, any zoom and any device pixel ratio, so that entire class of
 * defect cannot occur again. It is also cheaper: no data URI, no SVG rasterise.
 *
 * WHAT IT DRAWS. One set of fine lines at 58 degrees, 8px apart — an engraved
 * hatch, in one direction only. The client chose this from twenty candidates
 * built and compared on the running site, and the single direction is the
 * reason: crossed sets read as cloth, and a hatch that never crosses stays a
 * surface rather than becoming a pattern with a motif in it.
 *
 * Each line is TWO stops: a dark one and, immediately after it, a light one.
 * That pairing is the whole reason it reads as a material — the geometry looks
 * pressed into the surface rather than drawn on top of it, which is how blind
 * embossing works on paper. The light stop is the site's gold, not white:
 * white lines on black read as cheap, and the warmth is what the band was
 * missing.
 *
 * 58 degrees rather than 45, which would line up with nothing on this page but
 * would read as a deliberate diagonal; 58 reads as grain.
 *
 * ::before is the tonal ground under it — a real dark surface is unevenly lit
 * before it is textured, and the geometry sits on that rather than replacing it.
 * Both layers are under the content and inside the section's own stacking
 * context, so neither can touch the type or reach the page around it. */
.expertise-section {
  position: relative;
  color: #f5f0e7;
  background: var(--ink);
  isolation: isolate;
}

.expertise-section::before {
  content: "";
  position: absolute;
  z-index: -2;
  inset: 0;
  background:
    radial-gradient(120% 80% at 22% 0%, rgba(255, 247, 232, 0.06), transparent 60%),
    radial-gradient(90% 70% at 100% 100%, rgba(0, 0, 0, 0.45), transparent 55%);
  pointer-events: none;
}

.expertise-section::after {
  content: "";
  position: absolute;
  z-index: -1;
  inset: 0;
  background-image: none;
  pointer-events: none;
}

.expertise-section .section-heading {
  border-color: rgba(255, 255, 255, 0.55);
}

.expertise-section .section-link {
  color: rgba(255, 255, 255, 0.68);
}

.expertise-list {
  border-bottom: 1px solid rgba(255, 255, 255, 0.22);
}

.expertise-group {
  position: relative;
  /* Tightened from clamp(28px, 2.34375vw, 45px) at the client's direction, and
     the 80px first column is gone with the 01–04 it used to hold — leaving it
     would have been 80px of nothing in front of every heading. Between them
     the four groups give back about 130px of the band's height. */
  padding: clamp(22px, 1.82292vw, 35px) 0;
  display: grid;
  grid-template-columns: minmax(240px, 0.75fr) minmax(0, 1.25fr);
  gap: clamp(24px, 3.125vw, 60px);
  border-top: 1px solid rgba(255, 255, 255, 0.22);
  transition: background-color 450ms ease;
  @media (max-width: 1180px) {
    /* Scaled rather than pinned. The value at 1180px is unchanged, so nothing
       moves on a tablet or anywhere wider; it only comes in as the screen
       narrows, which is the direction it should always have gone. */
    padding: clamp(19px, 3vw, 35px) 0;
    gap: clamp(24px, 3.4vw, 60px);
  }
}

.expertise-group:first-child {
  border-top: 0;
}

.expertise-group::before {
  content: "";
  position: absolute;
  inset: 0 calc((100vw - var(--page)) / -2);
  z-index: 0;
  opacity: 0;
  background: rgba(255, 255, 255, 0.045);
  transition: opacity 350ms ease;
}

.expertise-group:hover::before {
  opacity: 1;
}

.expertise-group > * {
  position: relative;
  z-index: 1;
}

.group-number {
  padding-top: 6px;
  color: #c9aa70;
  font-size: clamp(10px, 0.5952vw, 18px);
  font-weight: 700;
  letter-spacing: 0.15em;
}

/* 0.68 of the section heading. It was clamp(25px, 2.4vw, 37px), which worked under a
   78px heading and would be 0.84 of the 44px one — a section title barely outranking
   the four items listed beneath it. The section steps down as a whole, not in parts. */
.expertise-group h3 {
  margin: 0;
  font-family: var(--serif);
  font-size: clamp(21px, 1.5625vw, 30px);
  font-weight: 400;
  letter-spacing: -0.025em;
  line-height: 1.12;
  @media (max-width: 1180px) {
    font-size: clamp(21px, 2vw, 30px);
  }
}

/* Two sub-columns, but only when two of them are still wide enough to read.
   `columns: 2 170px` is a maximum, not a count: the browser drops to one column
   as soon as two would be narrower than 170px. A flat `columns: 2` inside the
   reading band gave 152px sub-columns at 1280 and put service names like
   "Residential and Commercial Real Estate Transactions" on three lines. */
.expertise-group ul {
  columns: 2 170px;
  column-gap: clamp(28px, 2.34375vw, 45px);
  list-style: none;
  @media (max-width: 1180px) {
    column-gap: 45px;
  }
}

.expertise-group li {
  /* ONE VALUE SETS THE RHYTHM, and it is the line-height. There used to be a
     13px bottom margin here as well — more than a whole line on 12px type —
     which put the rows 2.23x the font size apart and made the list read loose
     when the leading already said 1.15.
     Removing it exposed the reason it had been there: "Residential and
     Commercial Real Estate Transactions" wraps on a phone, and at an even
     rhythm its second line is indistinguishable from the next practice area.
     Adding a gap back solves that, but it means two numbers decide one
     spacing, and the last item then carries a margin with nothing after it —
     so the same control also moves the bottom of the group, and neither can be
     tuned without disturbing the other.
     A HANGING INDENT SOLVES IT WITHOUT A SECOND NUMBER. The first line sits
     where it always did; a continuation is set in by one em and is obviously a
     continuation. The rhythm is then exactly the leading, everywhere, and the
     group's bottom spacing belongs to the group's padding alone. */
  margin: 0;
  padding-left: 1em;
  text-indent: -1em;
  break-inside: avoid;
  color: rgba(255, 255, 255, 0.63);
  font-size: 12px;
  line-height: 1.15;
  transition: color 250ms ease, transform 250ms ease;
}

.expertise-group li:hover {
  color: #e4c98f;
  transform: translateX(4px);
}

.awards-section {
  background: var(--paper-bright);
}

/* One award body per row, logo left, citations right — at every width.
   This used to be three side-by-side columns above 1180 and the stacked
   layout below it. Inside the reading band three columns can never work:
   the band caps at --band, so a column is at most 293px, of which the citation
   text gets about 110 — enough to break "Corporate/Commercial" across a line.
   The stacked layout was already drawn for tablets and it is the one that
   holds the citations on one or two lines, so it is now the only one. */
.awards-grid {
  display: grid;
  grid-template-columns: 1fr;
  border-top: 1px solid var(--line);
}

.award-column {
  padding: clamp(20px, 1.56vw, 30px) 32px 14px;
  display: grid;
  grid-template-columns: clamp(150px, 15.625vw, 200px) minmax(0, 1fr);
  gap: clamp(22px, 1.95vw, 28px);
  border-bottom: 1px solid var(--line);
  @media (max-width: 1180px) {
    /* Scaled rather than pinned. The value at 1180px is unchanged, so nothing
       moves on a tablet or anywhere wider; it only comes in as the screen
       narrows, which is the direction it should always have gone. */
    padding: clamp(24px, 3.8vw, 45px) 32px clamp(14px, 1.7vw, 20px);
    grid-template-columns: 200px minmax(0, 1fr);
    gap: clamp(20px, 3vw, 35px);
  }
}

.award-logo {
  height: clamp(71px, 5.98958vw, 115px);
  display: flex;
  align-items: flex-start;
  @media (max-width: 1180px) {
    height: 115px;
  }
}

/* ALB is a particularly wide, shallow wordmark. Keeping the shared logo well
   here makes its ranking list appear visually detached from the mark. */
.award-column:first-child .award-logo {
  height: 65px;
}

.award-logo img {
  max-width: clamp(108px, 9.11458vw, 175px);
  max-height: 80px;
  object-fit: contain;
  mix-blend-mode: multiply;
  filter: grayscale(1) contrast(1.08);
  @media (max-width: 1180px) {
    max-width: 175px;
  }
}

.award-column:nth-child(2) .award-logo img {
  max-width: 108px;
}

.award-column ol {
  list-style: none;
}

.award-column li {
  /* COMPACT — 2026-08-08, at the client's request.
   *
   * The row was `min-height: clamp(64px, 5.41667vw, 104px)` with 21px of
   * padding, and a citation is ONE LINE of 17px serif. At 2560 that is 104px
   * of row holding 62px of content: 42px of nothing, seventeen times over, and
   * the whole section ran to 2,171px. The min-height was there to give the
   * list a rhythm, which it still does at 56 — it just no longer scales the
   * emptiness with the screen.
   *
   * `align-items: center` because the leftover space used to pool below the
   * text: the year and the citation sat pinned to the top of a tall box, which
   * is what reads as loose even before you measure it. */
  min-height: clamp(44px, 2.6vw, 56px);
  padding: 13px 0;
  display: grid;
  align-items: center;
  /* minmax(0, 1fr), not 1fr: a grid track's automatic minimum is its content,
     so a long unbreakable run in the citation pushed the track past the row and
     overflowed the list by 12px at 1181px. */
  grid-template-columns: 84px minmax(0, 1fr);
  gap: 20px;
  border-top: 1px solid var(--line);
  @media (max-width: 1180px) {
    min-height: 104px;
  }
}

.award-column li span {
  color: var(--gold);
  font-size: clamp(10px, 0.5952vw, 18px);
  font-weight: 700;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.award-column li p {
  margin: 0;
  color: #4e4e48;
  font-family: var(--serif);
  font-size: 17px;
  line-height: 1.15;
  overflow-wrap: break-word;
}

.award-column .award-more {
  min-height: auto;
}

.network-section {
  padding: clamp(77px, 6.51042vw, 125px) var(--band-inset) clamp(80px, 6.77083vw, 130px);
  color: #f6f1e7;
  background: var(--ink-soft);
  @media (max-width: 1180px) {
    /* THE NARROW BANDS WERE PINNED TO THE CLAMP'S CEILING, which is the opposite
     of what a narrow screen needs: `clamp(64px, 5vw, 96px)` resolves to 64px at
     1181px, and this override then handed 96px to everything below — a 390px
     phone was getting half again the air a 1440px desktop gets, 95px above and
     95px below every section. Measured 2026-08-09: 760px of the homepage's
     11,390px on a phone was section padding alone.
     Scaling instead, and landing on the band above's 64px at the breakpoint so
     nothing jumps as the window crosses it. */
    padding: clamp(48px, 6.5vw, 77px) var(--band-inset) clamp(50px, 6.8vw, 80px);
  }
}

.network-intro {
  padding-bottom: 38px;
  display: block;
  border-bottom: 1px solid rgba(255, 255, 255, 0.25);
}

.network-intro > a {
  display: flex;
  gap: 18px;
  align-items: center;
  color: #d8ba80;
  font-size: clamp(10px, 0.5952vw, 18px);
  font-weight: 700;
  letter-spacing: 0.15em;
  text-transform: uppercase;
}

.network-stats {
  padding-top: 16px;
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 16px;
}

.network-stat {
  /* A RECTANGLE, AT EVERY WIDTH — 2026-08-08.
   *
   * This was `min-height: clamp(151px, 12.7604vw, 245px)`, and the fault is the
   * same mismatch the number inside it had: the HEIGHT tracked the viewport
   * while the WIDTH tracks the reading band, so the tile's proportion changed
   * as the screen did — 1.52 at 1680, 1.94 at 2560. It was never one shape.
   *
   * Locking the ratio instead of the height is what makes it a rectangle: 16/9
   * is the proportion the client pointed at. The min-height stays as a floor
   * for narrow screens, where 16/9 of a 225px tile is 127px and the number
   * plus its caption need more than that. */
  aspect-ratio: 16 / 9;
  min-height: clamp(151px, 8vw, 190px);
  /* A GRID TRACK'S AUTOMATIC MINIMUM IS ITS CONTENT, and the content here is a
     number that was being sized in fixed pixels — so the tile could not shrink
     below the width "18,000+" happened to need, and three of them held the
     whole page open. Measured 2026-08-09: 125px of horizontal overflow at
     320px, 85px at 360px, and 27px at 1024px, all of it this element. Letting
     the track shrink is half the fix; the other half is that the number must
     size itself FROM the tile, which is why the tile is a container. */
  min-width: 0;
  position: relative;
  overflow: hidden;
  /* The tile measures itself so the number can be sized from it — see
     `.network-stat strong`. */
  container-type: inline-size;
  padding: clamp(28px, 2.39583vw, 46px) 38px;
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  background-position: center;
  background-repeat: no-repeat;
  background-size: cover;
  isolation: isolate;
  @media (max-width: 1180px) {
    /* NO HEIGHT FLOOR HERE, and that is the fix rather than an omission.
       WITH `aspect-ratio` SET, A MIN-HEIGHT IS A MIN-WIDTH IN DISGUISE: 245px
       at 16/9 is a 436px floor on the WIDTH, and three of those cannot fit the
       1009px this section gets at a 1024px screen — measured 2026-08-09, 27px
       of the page hanging off the right edge, and the grid tracks had already
       shrunk to 189px underneath a tile that would not.

       The floor existed to keep room for a number sized in fixed pixels. The
       number is sized from the tile now, so the ratio can be left to decide the
       height and nothing has to be guessed. */
    padding: clamp(24px, 3.6vw, 46px) clamp(20px, 3vw, 38px);
  }
}

.network-stat + .network-stat {
  padding-left: 38px;
  border-left: 0;
}

.network-stat:nth-child(1) {
  background-image: url("assets/live-stat-cities-ink-v2.jpg");
}

.network-stat:nth-child(2) {
  background-image: url("assets/live-stat-partners-ink-v2.jpg");
}

.network-stat:nth-child(3) {
  background-image: url("assets/live-stat-lawyers-ink-v2.jpg");
}

.network-stat::before {
  content: "";
  position: absolute;
  z-index: -1;
  inset: 0;
  background:
    linear-gradient(180deg, rgba(12, 14, 14, 0.08), rgba(12, 14, 14, 0.76)),
    linear-gradient(90deg, rgba(12, 14, 14, 0.36), transparent 72%);
}

.network-stat::after {
  content: "";
  position: absolute;
  z-index: -1;
  inset: 0;
  border: 1px solid rgba(255, 255, 255, 0.25);
  pointer-events: none;
}

.network-stat strong {
  display: block;
  color: #e1c590;
  font-family: var(--serif);
  /* SIZED FROM THE TILE, NOT THE VIEWPORT — 2026-08-08.
   *
   * This was `clamp(58px, 4.79167vw, 92px)`, and "18,000+" ran out of its tile
   * at EVERY desktop width from 1180 to 1920 — by 26px at 1920, 41 at 1440, 99
   * at 1180. It only fitted at 2560 and up, and only because the reading band
   * had just been widened to 1460 and taken the tiles with it.
   *
   * The reason is a mismatch, not a wrong number: the type was driven by the
   * VIEWPORT while its container is driven by the BAND — three columns of
   * (band - 32px) / 3, less 38px of padding a side. Those two scale
   * differently, so no vw value can be right at more than one width. `cqw`
   * measures the thing the text actually has to fit inside.
   *
   * The arithmetic, and the thing worth knowing: **cqw is a percentage of the
   * container's CONTENT box**, not its border box — the 38px of padding a side
   * is already taken out. So the width the text must fit into is exactly
   * 100cqw, and no separate subtraction is needed. Getting that wrong the
   * first time double-counted the padding and drove the number to its floor.
   *
   * "18,000+" sets 3.51x its font-size in this face at this tracking
   * (measured: 323px at 92px). Fitting it in 100cqw gives 28.5cqw; 26cqw is
   * that with about 9% of slack, so a longer string than today's longest still
   * has somewhere to go. The 92px cap is unchanged — nothing is smaller than
   * it was at any width where it already fitted. */
  font-size: clamp(34px, 26cqw, 92px);
  font-weight: 400;
  letter-spacing: -0.055em;
  line-height: 0.9;
}

.network-stat span {
  display: block;
  margin-top: 24px;
  color: rgba(255, 255, 255, 0.57);
  font-size: 12px;
  font-weight: 700;
  letter-spacing: 0.16em;
  text-transform: uppercase;
}

.site-footer {
  padding: clamp(49px, 4.16667vw, 80px) 0 28px;
  background: var(--paper);
  @media (max-width: 1180px) {
    padding: 80px 0 28px;
  }
}

.acknowledgement {
  width: var(--page);
  max-width: clamp(651px, 55.2083vw, 1060px);
  margin: 0 auto clamp(52px, 4.375vw, 84px);
  display: grid;
  grid-template-columns: 80px 1fr;
  gap: clamp(25px, 2.08333vw, 40px);
  align-items: center;
  @media (max-width: 1180px) {
    max-width: 1060px;
    margin: 0 auto 84px;
    gap: 40px;
  }
}

.ack-mark {
  color: var(--gold);
}

.ack-mark svg {
  fill: none;
  stroke: currentColor;
  stroke-linecap: round;
  stroke-linejoin: round;
  stroke-width: 0.8;
}

.acknowledgement p {
  margin: 0;
  font-family: var(--serif);
  font-size: clamp(24px, 2.03125vw, 39px);
  font-style: italic;
  letter-spacing: -0.02em;
  line-height: 1.15;
  text-align: center;
  @media (max-width: 1180px) {
    font-size: clamp(24px, 2.6vw, 39px);
  }
}

.global-team-banner {
  min-height: clamp(141px, 11.9792vw, 230px);
  position: relative;
  margin-top: clamp(49px, 4.16667vw, 80px);
  padding: clamp(36px, 3.02083vw, 58px) var(--band-inset);
  display: grid;
  place-items: center;
  overflow: hidden;
  color: #fff;
  background: url("assets/footer-global-team.jpg") center 48% / cover no-repeat;
  isolation: isolate;
  @media (max-width: 1180px) {
    min-height: 230px;
    margin-top: 80px;
    padding: 58px var(--band-inset);
  }
}

.global-team-banner::before {
  content: "";
  position: absolute;
  z-index: -1;
  inset: 0;
  background: rgba(37, 30, 22, 0.32);
}

.global-team-banner h2 {
  max-width: clamp(590px, 50vw, 960px);
  margin: 0;
  font-family: var(--serif);
  font-size: clamp(35px, 3.4375vw, 66px);
  font-weight: 400;
  letter-spacing: -0.04em;
  line-height: 1.05;
  text-align: center;
  text-shadow: 0 3px 22px rgba(30, 22, 13, 0.26);
  @media (max-width: 1180px) {
    max-width: 960px;
    font-size: clamp(35px, 4.3vw, 66px);
  }
}

.footer-bottom {
  width: var(--page);
  margin: 0 auto;
  padding-top: 24px;
  display: flex;
  align-items: center;
  justify-content: flex-start;
  gap: clamp(15px, 1.25vw, 24px);
  border-top: 1px solid var(--line);
  color: var(--muted);
  font-size: clamp(10px, 0.5952vw, 18px);
  font-weight: 650;
  letter-spacing: 0.13em;
  text-transform: uppercase;
  @media (max-width: 1180px) {
    gap: 24px;
  }
}

.footer-legal {
  display: flex;
  flex-wrap: wrap;
  gap: 16px 28px;
}

/* The tap target, not the type. At 10px these links stood 14px tall, under the
   24px WCAG 2.5.8 asks for and well under the 44px a thumb actually needs. The
   padding is cancelled by an equal negative margin, so the target grows into the
   footer's own padding and the layout does not move a pixel. Safe to expand
   vertically because this row never wraps — there is no link above or below for
   the enlarged area to steal a tap from. */
.footer-legal a,
.footer-cookie-settings {
  display: inline-block;
  padding-block: 15px;
  margin-block: -15px;
}

.footer-cookie-settings {
  appearance: none;
  border: 0;
  background: none;
  color: inherit;
  padding-inline: 0;
  font: inherit;
  letter-spacing: inherit;
  text-transform: inherit;
  cursor: pointer;
}

.footer-cookie-settings:hover,
.footer-cookie-settings:focus-visible {
  color: var(--ink);
}

/* The consent choice is site-wide, but deliberately does not pretend to be a
   legal document. It explains the one browser choice in a compact, highly
   legible frost card; the assistant's own terms remain inside the assistant. */
.cookie-consent {
  position: fixed;
  z-index: 260;
  inset: 0;
  padding: 24px;
  display: flex;
  align-items: flex-end;
  justify-content: center;
  opacity: 0;
  pointer-events: none;
  transition: opacity 260ms ease;
}

.cookie-consent::before {
  content: "";
  position: absolute;
  inset: 0;
  background: rgba(21, 21, 18, 0.08);
  pointer-events: none;
}

.cookie-consent.is-visible {
  opacity: 1;
}

.cookie-consent__glass {
  width: min(760px, 100%);
  position: relative;
  padding: 22px 24px 20px;
  border: 1px solid rgba(255, 255, 255, 0.72);
  border-radius: 12px;
  background: rgba(247, 245, 239, 0.78);
  box-shadow:
    0 24px 70px rgba(26, 24, 20, 0.17),
    inset 0 1px 0 rgba(255, 255, 255, 0.72);
  backdrop-filter: blur(30px) saturate(1.18);
  -webkit-backdrop-filter: blur(30px) saturate(1.18);
  pointer-events: auto;
  transform: translateY(14px);
  transition: transform 420ms cubic-bezier(0.22, 1, 0.36, 1);
}

.cookie-consent.is-visible .cookie-consent__glass {
  transform: translateY(0);
}

.cookie-consent__eyebrow {
  margin: 0 0 8px;
  color: var(--gold);
  font-size: clamp(9px, 0.5357vw, 16.2px);
  font-weight: 700;
  letter-spacing: 0.15em;
  text-transform: uppercase;
}

.cookie-consent h2 {
  margin: 0;
  font-family: var(--serif);
  font-size: clamp(15px, 1.25vw, 24px);
  font-weight: 400;
  letter-spacing: -0.025em;
  @media (max-width: 1180px) {
    font-size: 24px;
  }
}

.cookie-consent__glass > p:not(.cookie-consent__eyebrow) {
  max-width: clamp(412px, 34.8958vw, 670px);
  margin: 9px 0 17px;
  color: #5e5c55;
  font-size: 12.5px;
  line-height: 1.15;
  @media (max-width: 1180px) {
    max-width: 670px;
  }
}

.cookie-consent__actions {
  display: flex;
  flex-wrap: wrap;
  gap: 9px;
}

.cookie-consent__actions button {
  min-height: 39px;
  padding: 0 15px;
  border: 1px solid #20211e;
  cursor: pointer;
  font-size: clamp(11px, 0.6548vw, 19.8px);
  font-weight: 650;
  transition: color 180ms ease, background-color 180ms ease, border-color 180ms ease;
}

.cookie-consent__accept {
  color: #fbf8f0;
  background: #20211e;
}

.cookie-consent__accept:hover,
.cookie-consent__accept:focus-visible {
  color: #20211e;
  background: #dfbd7e;
  border-color: #dfbd7e;
}

.cookie-consent__decline {
  color: #383934;
  background: rgba(255, 255, 255, 0.28);
}

.cookie-consent__decline:hover,
.cookie-consent__decline:focus-visible {
  border-color: #987344;
  color: #754834;
}

.ask-yk {
  position: fixed;
  z-index: 190;
  right: 28px;
  bottom: 28px;
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  pointer-events: none;
}

.ask-yk__launcher,
.ask-yk__dialog {
  pointer-events: auto;
}

.ask-yk__launcher {
  min-height: 58px;
  padding: 8px 12px 8px 8px;
  display: inline-flex;
  align-items: center;
  gap: 10px;
  border: 1px solid rgba(248, 244, 236, 0.16);
  border-radius: 2px;
  color: #fbf8f0;
  background: rgba(22, 24, 23, 0.96);
  box-shadow: 0 14px 38px rgba(20, 18, 15, 0.18);
  cursor: pointer;
  text-align: left;
  transition: transform 260ms cubic-bezier(0.22, 1, 0.36, 1), background-color 220ms ease, box-shadow 220ms ease;
}

.ask-yk__launcher:hover,
.ask-yk__launcher:focus-visible {
  transform: translateY(-3px);
  background: #2a2721;
  box-shadow: 0 18px 42px rgba(20, 18, 15, 0.28);
}

.ask-yk__launcher-mark {
  width: 40px;
  height: 40px;
  display: grid;
  place-items: center;
  color: #dfbd7e;
  background: rgba(223, 189, 126, 0.12);
}

.ask-yk__launcher-mark svg {
  width: 23px;
  height: 23px;
  fill: none;
  stroke: currentColor;
  stroke-linecap: square;
  stroke-linejoin: miter;
  stroke-width: 1.25;
}

.ask-yk__launcher-copy {
  display: grid;
  gap: 2px;
  font-family: var(--serif);
  font-size: 18px;
  letter-spacing: -0.02em;
  line-height: 1;
}

.ask-yk__launcher-copy small {
  color: rgba(248, 244, 236, 0.62);
  font-family: var(--sans);
  font-size: clamp(8px, 0.4762vw, 14.4px);
  font-weight: 700;
  letter-spacing: 0.14em;
  line-height: 1.15;
  text-transform: uppercase;
}

.ask-yk__launcher-arrow {
  margin-left: 7px;
  color: #dfbd7e;
  font-size: 17px;
  line-height: 1;
}

.ask-yk__dialog {
  width: min(420px, calc(100vw - 36px));
  max-height: min(760px, calc(100svh - 48px));
  position: absolute;
  right: 0;
  bottom: 0;
  display: flex;
  flex-direction: column;
  overflow: hidden;
  visibility: hidden;
  opacity: 0;
  transform: translate3d(0, 18px, 0) scale(0.972);
  /* The corner it shares with the ball. Scaling about it is what lets the panel and
     the folding ghost occupy the same box and hand over invisibly. */
  transform-origin: 100% 100%;
  border: 1px solid rgba(23, 24, 21, 0.2);
  border-radius: 2px;
  color: var(--ink);
  /* Opaque. At 98.5% the compositor had to blend the whole panel over the live hero
     canvas on every frame of the opening. */
  background: #fbfaf6;
  --ask-yk-header-h: 52px;
  box-shadow: 0 22px 66px rgba(15, 14, 11, 0.23);
  backface-visibility: hidden;
}

.ask-yk.is-open .ask-yk__dialog {
  visibility: visible;
  opacity: 1;
  transform: translate3d(0, 0, 0) scale(1);
}

/* Held for the whole visible life of the panel. Dropping will-change or the inline
   transform while it is on screen re-rasterises it, and that is a flash. */
.ask-yk__dialog.is-motion-live,
.ask-yk__dialog.is-motion-prepared {
  will-change: opacity, transform;
}

.ask-yk:not(.is-open) .ask-yk__dialog.is-motion-prepared {
  visibility: visible;
  opacity: 0.001;
  pointer-events: none;
}

/* The panel is one continuous surface from its top edge to its bottom one. Nothing here
   carries a fill of its own — a second colour at the top is what the fold cannot hide. */
.ask-yk__header {
  min-height: var(--ask-yk-header-h);
  padding: 13px 14px 12px 18px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 14px;
  color: var(--ink);
  background: #fbfaf6;
  border-bottom: 1px solid var(--line);
}

.ask-yk__header h2 {
  min-width: 0;
  margin: 0;
  display: flex;
  align-items: center;
  gap: 9px;
  font-family: var(--serif);
  font-size: 17px;
  font-weight: 400;
  letter-spacing: -0.02em;
  line-height: 1.1;
}

/* The assistant is listening. One dot, where a line of small caps used to say so. */
.ask-yk__live {
  flex: 0 0 auto;
  width: 5px;
  height: 5px;
  border-radius: 50%;
  background: var(--gold);
  box-shadow: 0 0 0 3px rgba(160, 123, 69, 0.13);
}

.ask-yk__header-actions {
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  gap: 6px;
}

.ask-yk__new {
  min-height: 24px;
  padding: 0 2px;
  border: 0;
  border-bottom: 1px solid transparent;
  color: var(--muted);
  background: transparent;
  cursor: pointer;
  font-size: clamp(8.5px, 0.506vw, 15.3px);
  font-weight: 700;
  letter-spacing: 0.1em;
  white-space: nowrap;
  text-transform: uppercase;
  transition: color 180ms ease, border-color 180ms ease;
}

.ask-yk__new:hover,
.ask-yk__new:focus-visible {
  color: var(--ink);
  border-bottom-color: var(--gold);
}

.ask-yk__close {
  width: 26px;
  height: 26px;
  display: grid;
  place-items: center;
  border: 0;
  color: var(--muted);
  background: transparent;
  cursor: pointer;
  transition: color 180ms ease;
}

.ask-yk__close svg {
  width: 13px;
  height: 13px;
  display: block;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.4;
  stroke-linecap: square;
}

.ask-yk__close:hover,
.ask-yk__close:focus-visible {
  color: var(--ink);
}

/* The body takes whatever height the panel has left, which is what keeps the input row
   on the panel's bottom edge when it is dragged larger. Without it the body stopped at
   the height of its own contents and everything stacked at the top of a tall empty box.

   `margin-top: auto` on the first child settles the conversation against the input
   instead of floating it at the top of the spare room — the newest thing said sits
   where you are about to reply to it. It is the scroll-safe way to do this: with
   `justify-content: flex-end` an overflowing conversation loses its head above the
   scroll origin, where nothing can reach it. */
.ask-yk__body {
  flex: 1 1 auto;
  min-height: 0;
  padding: 16px 18px 15px;
  display: flex;
  flex-direction: column;
  overflow-y: auto;
}

.ask-yk__body > :first-child {
  margin-top: auto;
}

.ask-yk__intro {
  margin: 0 0 17px;
  color: var(--muted);
  font-size: 13px;
  line-height: 1.15;
}

/* One scroll region in the panel, not two. This used to be capped at 330px and scroll
   inside itself, so dragging the panel taller made the panel taller and left the
   conversation in the same small box. The body scrolls; this just grows. */
.ask-yk__messages {
  display: grid;
  gap: 10px;
}

.ask-yk__dialog.has-conversation .ask-yk__intro {
  display: none;
}

.ask-yk__message {
  width: fit-content;
  max-width: 92%;
  padding: 11px 12px;
  border: 1px solid var(--line);
  font-size: 13px;
  line-height: 1.15;
}

.ask-yk__message span {
  display: block;
  margin-bottom: 4px;
  color: var(--gold);
  font-size: clamp(8px, 0.4762vw, 14.4px);
  font-weight: 700;
  letter-spacing: 0.13em;
  text-transform: uppercase;
}

.ask-yk__message p {
  margin: 0;
}

.ask-yk__message--assistant {
  background: #f3f0e8;
}

.ask-yk__message--user {
  justify-self: end;
  color: #fbf8f0;
  border-color: #2a2b27;
  background: #2a2b27;
}

.ask-yk__message--user span {
  color: rgba(251, 248, 240, 0.62);
}

.ask-yk__message--typing p {
  display: flex;
  gap: 4px;
}

.ask-yk__message--typing i {
  width: 4px;
  height: 4px;
  display: block;
  border-radius: 50%;
  background: var(--gold);
  animation: ask-yk-pulse 900ms infinite alternate;
}

.ask-yk__message--typing i:nth-child(2) {
  animation-delay: 140ms;
}

.ask-yk__message--typing i:nth-child(3) {
  animation-delay: 280ms;
}

.ask-yk__message--response {
  border-color: #cbb58a;
  background: #fbf7ee;
}

.ask-yk__message--response a {
  margin-top: 10px;
  display: block;
  color: #754834;
  font-size: 12px;
  font-weight: 700;
  line-height: 1.15;
}

.ask-yk__message--response a:hover {
  color: var(--gold);
}

.ask-yk__sources {
  margin-top: 9px;
  display: grid;
  gap: 5px;
}

.ask-yk__sources a {
  color: #754834;
  font-size: clamp(10.5px, 0.625vw, 18.9px);
  font-weight: 650;
  line-height: 1.15;
  text-decoration: underline;
  text-decoration-color: rgba(117, 72, 52, 0.3);
  text-underline-offset: 2px;
}

.ask-yk__sources a:hover {
  color: var(--gold);
}

.ask-yk__handoff {
  min-height: 34px;
  margin-top: 10px;
  padding: 0 11px;
  border: 1px solid #8d6a42;
  color: #754834;
  background: transparent;
  cursor: pointer;
  font-size: clamp(10.5px, 0.625vw, 18.9px);
  font-weight: 700;
}

.ask-yk__handoff:hover,
.ask-yk__handoff:focus-visible {
  color: #fbf8f0;
  background: #754834;
}

.ask-yk__suggestions {
  margin-top: 13px;
  display: flex;
  flex-wrap: wrap;
  gap: 7px;
}

.ask-yk__suggestions button {
  padding: 7px 8px;
  border: 1px solid var(--line);
  color: #56554d;
  background: transparent;
  cursor: pointer;
  font-size: clamp(10px, 0.5952vw, 18px);
  letter-spacing: 0.01em;
  transition: color 180ms ease, border-color 180ms ease, background-color 180ms ease;
}

.ask-yk__suggestions button:hover,
.ask-yk__suggestions button:focus-visible {
  border-color: #af8650;
  color: #754834;
  background: #f4eee4;
}

.ask-yk__form {
  min-height: 61px;
  padding: 8px 10px 8px 18px;
  display: grid;
  grid-template-columns: minmax(0, 1fr) 36px;
  align-items: end;
  border-top: 1px solid var(--line);
  background: #fffefb;
}

.ask-yk__form textarea {
  width: 100%;
  min-height: 36px;
  max-height: 92px;
  min-width: 0;
  padding: 7px 8px 6px 0;
  overflow-y: auto;
  border: 0;
  outline: 0;
  resize: none;
  color: var(--ink);
  background: transparent;
  font-family: var(--serif);
  /* Was 16px, a hair off the panel title's 17 — the placeholder read as a second
     heading. It is where you type, not the loudest thing in the window. */
  font-size: 14px;
  line-height: 1.15;
}

.ask-yk__form textarea::placeholder {
  color: #78766d;
}

.ask-yk__form button {
  width: 36px;
  height: 36px;
  align-self: center;
  display: grid;
  place-items: center;
  border: 0;
  color: #fbf8f0;
  background: #1a1b19;
  cursor: pointer;
  transition: color 180ms ease, background-color 180ms ease, transform 180ms ease;
}

.ask-yk__form button:hover,
.ask-yk__form button:focus-visible {
  color: #1a1b19;
  background: #dfbd7e;
  transform: translate(1px, -1px);
}

.ask-yk__form button:disabled {
  color: rgba(251, 248, 240, 0.55);
  background: #67665f;
  cursor: wait;
  transform: none;
}

.ask-yk__form button svg {
  width: 18px;
  height: 18px;
  fill: none;
  stroke: currentColor;
  stroke-linecap: square;
  stroke-linejoin: miter;
  stroke-width: 1.5;
}

.ask-yk__lead {
  position: absolute;
  z-index: 8;
  inset: 83px 0 0;
  padding: 18px;
  display: grid;
  align-content: start;
  gap: 11px;
  overflow-y: auto;
  background: rgba(251, 250, 246, 0.99);
}

.ask-yk__lead-head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 12px;
}

.ask-yk__lead-head span {
  color: var(--gold);
  font-size: clamp(8px, 0.4762vw, 14.4px);
  font-weight: 700;
  letter-spacing: 0.13em;
  text-transform: uppercase;
}

.ask-yk__lead h3 {
  margin: 5px 0 0;
  font-family: var(--serif);
  font-size: clamp(15px, 1.30208vw, 25px);
  font-weight: 400;
  @media (max-width: 1180px) {
    font-size: 25px;
  }
}

.ask-yk__lead-head button {
  border: 0;
  color: #51514b;
  background: transparent;
  cursor: pointer;
  font-size: clamp(15px, 1.25vw, 24px);
  @media (max-width: 1180px) {
    font-size: 24px;
  }
}

.ask-yk__lead > p {
  margin: 0;
  color: var(--muted);
  font-size: clamp(11px, 0.6548vw, 19.8px);
  line-height: 1.15;
}

.ask-yk__lead label {
  display: grid;
  gap: 5px;
}

.ask-yk__lead label > span {
  color: #5f5e57;
  font-size: clamp(9px, 0.5357vw, 16.2px);
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.ask-yk__lead input {
  width: 100%;
  min-height: 40px;
  padding: 8px 10px;
  border: 1px solid var(--line);
  color: var(--ink);
  background: #fffefb;
  outline: 0;
}

.ask-yk__lead input:focus {
  border-color: #9b7547;
  box-shadow: 0 0 0 2px rgba(155, 117, 71, 0.13);
}

.ask-yk__lead-submit {
  min-height: 42px;
  margin-top: 3px;
  border: 0;
  color: #fbf8f0;
  background: #1a1b19;
  cursor: pointer;
  font-size: clamp(11px, 0.6548vw, 19.8px);
  font-weight: 700;
}

.ask-yk__lead-submit:hover,
.ask-yk__lead-submit:focus-visible {
  color: #1a1b19;
  background: #dfbd7e;
}

.ask-yk__lead-status {
  min-height: 16px;
  color: #754834 !important;
}

.ask-yk__honeypot {
  position: absolute !important;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
}

.ask-yk__disclaimer {
  margin: 0;
  padding: 0 18px 13px;
  color: #848078;
  font-size: clamp(9px, 0.5357vw, 16.2px);
  letter-spacing: 0.05em;
}

/* The consent card blurs the conversation behind it, and used to disable it too —
   every child except the card got `pointer-events: none`, the header among them, so
   the close button could not be pressed until Accept was. A consent notice that
   cannot be dismissed is not a choice. The header stays live and unblurred; there is
   nothing to read in it and nothing to consent to. */
/* The grip joins the header in staying live. Resizing the window is not something to
   consent to, and it was caught by this rule exactly as the close button was. */
.ask-yk__dialog:not(.is-consented) > :not(.ask-yk__terms):not(.ask-yk__header):not(.ask-yk__grip) {
  filter: blur(9px);
  opacity: 0.48;
  pointer-events: none;
  user-select: none;
  transition: filter 420ms ease, opacity 360ms ease;
}
.ask-yk__dialog:not(.is-consented) > .ask-yk__header {
  position: relative;
  z-index: 21;
}
/* "New chat" has nothing to start until there is consent; close always has work. */
.ask-yk__dialog:not(.is-consented) .ask-yk__new { opacity: 0.35; pointer-events: none; }

.ask-yk__dialog.is-consented > :not(.ask-yk__terms):not(.ask-yk__header):not(.ask-yk__grip) {
  filter: blur(0);
  opacity: 1;
  transition: filter 500ms ease, opacity 420ms ease;
}

/* While the panel is arriving or leaving, the timeline owns its blocks' opacity frame by
   frame. The consent transition above would chase those writes with a 360ms lag: the
   entrance would crawl in behind it and the exit would still be half visible when the
   folding box takes over. Short-lived — dropped the moment the motion ends, so accepting
   the terms still gets its own transition. */
.ask-yk__dialog.is-motion-driven > * {
  /* !important because the consent rule above carries three :not() classes and outweighs
     anything reasonable here. This one is short-lived and owns opacity outright. */
  transition: none !important;
}

.ask-yk__terms {
  position: absolute;
  z-index: 20;
  /* Below the title line rather than under it: the header is opaque, so a gate that
     starts at the panel's top edge has its own eyebrow hidden behind it. */
  inset: var(--ask-yk-header-h) 0 0;
  padding: 18px;
  display: grid;
  place-items: center;
  overflow-y: auto;
  /* No backdrop-filter. The panel underneath is already held at blur(9px) and 48%, so
     a second 15px backdrop blur added almost nothing to look at while forcing the whole
     panel to be re-blurred on every frame of the opening — which cost the opening its
     first 58ms outright. */
  background: rgba(238, 236, 229, 0.55);
}

/* The gate is centred while it fits and top-aligned once it does not. Centring an item
   taller than its scroller pushes its head above the scroll origin, where nothing can
   reach it — on a 360-wide phone that is the title. */
.ask-yk__terms {
  align-items: safe center;
}

.ask-yk__terms-card {
  width: 100%;
  padding: 22px 21px 20px;
  border: 1px solid rgba(255, 255, 255, 0.82);
  border-radius: 8px;
  background: rgba(252, 251, 247, 0.87);
  box-shadow:
    0 18px 52px rgba(22, 21, 18, 0.16),
    inset 0 1px 0 rgba(255, 255, 255, 0.84);
}

.ask-yk__terms-eyebrow {
  margin: 0 0 8px;
  color: var(--gold);
  font-size: clamp(8.5px, 0.506vw, 15.3px);
  font-weight: 700;
  letter-spacing: 0.14em;
  text-transform: uppercase;
}

.ask-yk__terms h3 {
  margin: 0;
  font-family: var(--serif);
  font-size: clamp(15px, 1.25vw, 24px);
  font-weight: 400;
  letter-spacing: -0.025em;
  line-height: 1.08;
  @media (max-width: 1180px) {
    font-size: 24px;
  }
}

.ask-yk__terms-card > p:not(.ask-yk__terms-eyebrow, .ask-yk__terms-status) {
  margin: 12px 0 15px;
  color: #5e5d56;
  font-size: clamp(11px, 0.6548vw, 19.8px);
  line-height: 1.15;
}

.ask-yk__terms-check {
  display: grid;
  grid-template-columns: 17px minmax(0, 1fr);
  gap: 9px;
  align-items: start;
  color: #343530;
  cursor: pointer;
  font-size: clamp(11px, 0.6548vw, 19.8px);
  line-height: 1.15;
}

.ask-yk__terms-check input {
  width: 15px;
  height: 15px;
  margin: 1px 0 0;
  accent-color: #754834;
}

.ask-yk__terms-start,
.ask-yk__terms-cookie {
  width: 100%;
  min-height: 42px;
  margin-top: 15px;
  border: 0;
  color: #fbf8f0;
  background: #1a1b19;
  cursor: pointer;
  font-size: clamp(10.5px, 0.625vw, 18.9px);
  font-weight: 700;
}

/* Held at the foot of the card rather than after it. The terms run to six lines on a
   narrow phone and the card is taller than the panel it sits in; before this, the one
   control that starts anything began 28px below the panel's own bottom edge, reachable
   only by scrolling a card that gives no sign it scrolls. Read as much or as little of
   the terms as you like — the button stays where you left it. The negative offset is the
   card's own bottom padding, so it settles flush when there is nothing to scroll. */
.ask-yk__terms-start {
  position: sticky;
  bottom: -20px;
}

.ask-yk__terms-start:disabled {
  color: #8b8981;
  background: #d9d6ce;
  cursor: not-allowed;
}

.ask-yk__terms-cookie {
  color: #1a1b19;
  border: 1px solid #1a1b19;
  background: transparent;
}

.ask-yk__terms-privacy {
  margin-top: 10px;
  display: inline-block;
  color: #754834;
  font-size: clamp(9.5px, 0.5655vw, 17.1px);
  text-decoration: underline;
  text-underline-offset: 2px;
}

.ask-yk__terms-status {
  min-height: 16px;
  margin: 9px 0 0;
  color: #754834;
  font-size: clamp(9.5px, 0.5655vw, 17.1px);
  line-height: 1.15;
}

@keyframes ask-yk-pulse {
  from { opacity: 0.28; transform: translateY(1px); }
  to { opacity: 1; transform: translateY(-1px); }
}

@media (max-width: 1180px) {
  :root {
    --page: calc(100vw - 56px);
  }

  .site-header {
    padding-inline: 28px;
    grid-template-columns: 150px 1fr 38px;
    gap: 18px;
  }

  .site-brand {
    height: 44px;
  }

  .primary-menu {
    gap: 22px;
  }

  .primary-menu > li > a {
    font-size: 13px;
  }

  .hero-support {
    width: min(700px, 70vw);
    grid-template-columns: 1fr;
    gap: 32px;
  }

  /* These used to be flattened to a 28px gutter here, which is why the reading
     band was invisible on a tablet: every screen at or below 1180 threw the
     band away and ran the text edge to edge. The band is the point of these
     sections, so it holds down to the phone rules. */
  .news-stream,
  .about-section,
  .expertise-section,
  .awards-section,
  .network-section {
    padding-left: var(--band-inset);
    padding-right: var(--band-inset);
  }

  /* The three-across expertise row does not survive the band here: the list
     column ends up around 190px and every service name breaks to three lines.
     The heading takes the full measure beside its number and the list runs
     underneath it, which is the same information in the order it is read. */
  /* The number this column was reserved for is gone from the markup, so the
     heading takes the full measure and the list runs underneath it — which is
     what the note above already described, minus 72px of nothing. */
  .expertise-group {
    grid-template-columns: minmax(0, 1fr);
    gap: clamp(20px, 2.6vw, 34px);
  }

  .expertise-group::before {
    inset-inline: calc(var(--band-inset) * -1);
  }

  /* The mark-and-themes rail beside the copy costs 250px of a band that is only
     614px at 1024 and 460px at 768, which left the prose a 338px measure and
     pushed the bilingual closing line past its own edge. The rail lies down
     above the copy instead — the arrangement the phone layout already used —
     and the copy gets the whole band. */
  .about-layout {
    grid-template-columns: minmax(0, 1fr);
    gap: clamp(40px, 4.4vw, 52px);
  }

  .about-rail {
    position: static;
    top: auto;
    width: 100%;
    display: grid;
    grid-template-columns: 150px minmax(0, 1fr);
    gap: 30px;
    align-items: start;
  }

  .about-mark {
    width: 150px;
  }

  /* Beside the mark rather than under it, so the 48px that used to separate
     them vertically is now dead space, and 248px of track spreads three labels
     over a gap and a half. Both come down to the height the mark actually is. */
  .about-themes-wrap {
    min-height: 186px;
    margin: 0 0 0 12px;
  }

  .about-themes {
    min-height: 186px;
  }
}

@media (max-width: 960px) {
  :root {
    /* 78 since 2026-08-11, the same +15% the desktop bar took — 68 x 1.15 is
       78.2. The narrow bar is the TALLER of the two and always has been: below
       960 the magnifier comes back into the row, so there are three things to
       fit rather than two. Raising only the base value would have inverted
       that relationship at exactly the widths where the row is busiest. */
    --header-height: 78px;
  }

  .site-header {
    height: var(--header-height);
    /* Three tracks, not two: the magnifier is back in the bar at this width. */
    grid-template-columns: 1fr auto auto;
    gap: 14px;
  }

  .site-brand {
    height: 46px;
  }

  /* Search used to be hidden here with nothing put in its place, so every phone
     and tablet downloaded the 52KB index with no way to open it. The magnifier is
     38px and the bar has room for it beside the menu button.
     Columns assigned explicitly: the menu button precedes the nav and the search
     in the markup, so auto-placement would otherwise put it in the middle. */
  /* `grid-row: 1` on all three, not just a column each. The markup order is
     brand, menu button, nav, search — so with columns alone, sparse auto-placement
     put the menu button in column 3, advanced its cursor past column 2, and then
     had nowhere left in row 1 for the search glyph, which dropped to a second row
     below the bar. Pinning the row keeps all three in the header. */
  .site-brand { grid-column: 1; grid-row: 1; }
  .header-search { grid-column: 2; grid-row: 1; justify-self: end; }
  .menu-toggle { grid-column: 3; grid-row: 1; }

  .menu-toggle {
    width: 42px;
    height: 42px;
    padding: 11px 7px;
    display: flex;
    flex-direction: column;
    justify-content: center;
    gap: 7px;
    border: 0;
    background: transparent;
    cursor: pointer;
  }

  .menu-toggle span:not(.sr-only) {
    width: 27px;
    height: 1px;
    display: block;
    background: var(--ink);
    transition: transform 350ms ease;
  }

  .menu-toggle[aria-expanded="true"] span:first-child {
    transform: translateY(4px) rotate(45deg);
  }

  .menu-toggle[aria-expanded="true"] span:nth-child(2) {
    transform: translateY(-4px) rotate(-45deg);
  }

  .primary-navigation {
    /* `justify-self: end` is set for the desktop grid and was never reset here.
       This is still a grid item, so Chrome honoured that alignment over the
       `left: 0 / right: 0` below and the "full screen" menu rendered as a 196px
       column pinned to the right at 390 — leaving most of the page visible and
    clickable beside an open modal navigation. */
    justify-self: stretch;
    width: 100vw;
    position: fixed;
    z-index: 95;
    inset: var(--header-height) auto 0 0;
    height: calc(100svh - var(--header-height));
    padding: 38px 28px 70px;
    visibility: hidden;
    overflow-y: auto;
    opacity: 0;
    transform: translateY(-14px);
    background: rgba(251, 250, 246, 0.99);
    transition:
      visibility 0s linear 350ms,
      opacity 280ms ease,
      transform 400ms cubic-bezier(0.22, 1, 0.36, 1);
  }

  .primary-navigation.is-open {
    visibility: visible;
    opacity: 1;
    transform: translateY(0);
    transition-delay: 0s;
  }

  .primary-menu {
    height: auto;
    display: block;
  }

  .primary-menu > li {
    height: auto;
    display: block;
    border-bottom: 1px solid var(--line);
  }

  .primary-menu > li > a {
    padding: 17px 0;
    display: flex;
    justify-content: space-between;
    font-family: var(--serif);
    font-size: 30px;
    font-weight: 400;
    letter-spacing: -0.02em;
  }

  .primary-menu > li > a::after {
    display: none;
  }

  .hero {
    /* Same floor as the desktop rule, and `100svh` restored: a fixed 820 here
       put the launcher under the fold on every phone held sideways. */
    min-height: max(620px, 100svh);
  }

  .hero-art {
    inset: 0;
    height: auto;
    background-position: 54% center;
  }

  .hero-reading-field {
    background:
      linear-gradient(90deg, rgba(248, 244, 236, 0.94), rgba(248, 244, 236, 0.76) 42%, rgba(248, 244, 236, 0.25) 72%, rgba(20, 15, 22, 0.08)),
      linear-gradient(180deg, rgba(248, 244, 236, 0.12), transparent 65%, rgba(19, 15, 20, 0.16));
  }

  .hero-inner {
    /* Between the 26px above and the 48px below that this replaces — one floor
       for both sides, as on the desktop rule. */
    --hero-band-gap: 38px;
    min-height: max(620px, 100svh);
    padding-top: clamp(104px, 15vh, 138px);
  }

  .hero h1 {
    font-size: clamp(65px, 10.8vw, 92px);
  }

  /* Sized so the longest of the quotations still lands on two lines inside the
     two-thirds measure. It was clamp(40px, 6.3vw, 57px) — at 768 that is 48px against a
     482px measure, which is 22 characters a line and three lines for a 57-character
     quotation. The measure here is what the composition leaves, so the type is the only
     thing that can give. */
  .hero h1.hero-quote {
    font-size: clamp(32px, 4.6vw, 47px);
  }

  .hero-support {
    width: min(680px, 80vw);
    grid-template-columns: 1fr;
    gap: 32px;
  }

  .hero-support h2 {
    max-width: 620px;
  }

  .news-card {
    min-height: 428px;
  }

  .network-stats {
    grid-template-columns: 1fr;
  }

  /* ONE COLUMN IS WHERE THE RATIO STOPS MAKING SENSE, and that is here at 960
     rather than at the phone breakpoint — measured 2026-08-09, a 700px window
     gave each tile 630px of width, so 16/9 made it 354px tall to hold 131px of
     type, and the section came to 902px against 584px on a 390px phone. The
     ratio earns its keep when three tiles sit side by side and it is what makes
     them a row; stacked, there is nothing for it to be consistent with. */
  .network-stat {
    aspect-ratio: auto;
    min-height: 0;
  }

  .network-stat strong {
    font-size: clamp(58px, 10vw, 82px);
  }

  /* The layout is already stacked from 1180 down; only the rail's own
     proportions change here. */
  .about-layout {
    gap: 44px;
  }

  .about-rail {
    grid-template-columns: 132px minmax(0, 1fr);
    gap: 24px;
  }

  .about-mark {
    width: 132px;
  }

  .about-themes-wrap {
    min-height: 168px;
    margin-left: 4px;
  }

  .about-themes {
    min-height: 168px;
  }

  .about-theme {
    gap: 14px;
    font-size: clamp(10px, 0.5952vw, 18px);
  }

  .about-copy p:first-child {
    margin-left: -34px;
  }

  .expertise-group {
    grid-template-columns: minmax(0, 1fr);
  }

  /* Below here the stacked list column is under ~400px, and two sub-columns
     put every second service name on three lines. One column, full measure. */
  .expertise-group ul {
    columns: 1;
  }

  .network-intro {
    grid-template-columns: 1fr;
    /* Scaled with the padding below it — see the note in the 680 band. 55px
       between a heading and a single line of type is a gap you notice before
       you read either of them. */
    gap: clamp(24px, 6vw, 55px);
  }
}

@media (max-width: 680px) {
  :root {
    --page: calc(100vw - 36px);
  }

  .site-header {
    padding-inline: 18px;
  }

  .site-brand {
    height: 38px;
  }

  .primary-navigation {
    padding-inline: 18px;
  }

  .primary-menu > li > a {
    font-size: 27px;
  }

  .hero {
    min-height: 790px;
  }

  .hero-art {
    inset: 0;
    height: auto;
    opacity: 1;
    background-position: 54% center;
  }

  .hero-reading-field {
    background:
      linear-gradient(180deg, rgba(248, 244, 236, 0.86), rgba(248, 244, 236, 0.72) 48%, rgba(248, 244, 236, 0.32) 72%, rgba(20, 15, 22, 0.1)),
      linear-gradient(90deg, rgba(248, 244, 236, 0.58), rgba(248, 244, 236, 0.12));
  }

  .hero-inner {
    /* Between the 22–96px above and the 36px below that this replaces. The hero is
       taller than the screen here, so the floor is the number most likely to be the
       visible gap rather than a floor under free space. */
    --hero-band-gap: 30px;
    min-height: 790px;
    padding-top: 126px;
    padding-bottom: 38px;
  }

  .hero h1 {
    font-size: clamp(50px, 14vw, 67px);
    line-height: 0.98;
  }

  /* One size, and it is smaller than what it replaces, for the reason the desktop rules
     had backwards: `--long` was 46px and `--very-long` 43px against a 39px base, so the
     quotations with the most words to fit were given the least room per word. On a
     360px phone that is three lines. This holds every one of the ten to two. */
  .hero h1.hero-quote {
    font-size: clamp(25px, 7.3vw, 50px);
    padding: 0.09em 0.02em 0.24em;
    line-height: 1.24;
  }

  .hero.hero-wisdom--long .hero-inner {
    --hero-band-gap: 22px;
  }

  .hero-strategy-line {
    font-size: clamp(10px, 0.5952vw, 18px);
    letter-spacing: 0.13em;
  }

  .hero-quote__zh {
    margin-top: 18px;
    font-size: 17px;
    line-height: 1.3;
  }

  .hero-quote__by {
    margin-top: 14px;
    font-size: clamp(9px, 0.5357vw, 16.2px);
  }

  .hero-support {
    width: 100%;
    gap: 26px;
  }

  .hero-support h2 {
    font-size: 19px;
  }

  .hero-ask-launch {
    width: 100%;
    padding-block: 13px;
  }

  .hero-ask-launch__prompt {
    font-size: 18px;
  }

  .ask-yk {
    right: 18px;
    bottom: 18px;
  }

  .ask-yk__dialog {
    max-height: calc(100svh - 100px);
    display: flex;
    flex-direction: column;
  }

  .ask-yk__body {
    min-height: 0;
    overflow-y: auto;
  }

  .ask-yk__launcher {
    min-height: 54px;
  }

  .ask-yk__launcher-mark {
    width: 38px;
    height: 38px;
  }

  .ask-yk__launcher-copy {
    font-size: 17px;
  }

  .ask-yk__launcher-arrow {
    margin-left: 2px;
  }

  .cookie-consent {
    padding: 12px;
  }

  .cookie-consent__glass {
    padding: 18px;
  }

  .cookie-consent h2 {
    font-size: 21px;
  }

  .news-stream,
  .about-section,
  .expertise-section,
  .awards-section,
  .network-section {
    padding-left: 18px;
    padding-right: 18px;
  }

  .news-stream {
    padding-top: 25px;
    /* Scaled with the sections below it. Left at a flat 95px it became the one
       loose gap on an otherwise tightened page — a rhythm is only a rhythm if
       nothing in it is exempt. */
    padding-bottom: clamp(44px, 12vw, 95px);
  }

  .news-grid {
    grid-template-columns: 1fr;
  }

  .news-card {
    min-height: auto;
    padding: 22px 18px 24px;
    border-left: 0;
    border-right: 1px solid var(--line);
  }

  .news-visual {
    height: 190px;
    margin: -22px -18px 24px;
  }

  .news-card::before {
    inset-inline: 0;
  }

  .news-card h2 {
    font-size: 25px;
  }

  .news-card .text-link {
    margin-top: 28px;
  }

  .about-section,
  /* `.expertise-section, .awards-section { padding: 95px 0 }` used to sit here.
     Both are gone: the 1180 band above now scales, and pinning the padding
     again on the smallest screens is exactly what made the page loose. */

  .section-heading {
    /* No padding override: 23px under a 30px heading is 0.77em, the same slackness
       the desktop rule had. The clamp's 14px floor keeps the 0.47. */
    align-items: flex-end;
  }

  /* No override. It read `font-size: 47px`, which was a hair under the old 48px floor
     and is now larger than the desktop cap — a phone would have been given a bigger
     section heading than a 2560px screen. The clamp's own floor, 30px, is 0.68 of the
     h1's floor: the same ratio the rest of the scale holds. */

  .section-heading h2 span {
    margin-top: 8px;
    display: block;
    font-size: 18px;
  }

  .section-link {
    max-width: 118px;
    justify-content: flex-end;
    text-align: right;
  }

  .about-layout {
    padding-top: 45px;
    grid-template-columns: 1fr;
    gap: 48px;
  }

  .about-rail {
    position: static;
    top: auto;
    width: 100%;
    display: grid;
    grid-template-columns: 126px minmax(0, 1fr);
    gap: 22px;
    align-items: start;
  }

  .about-mark {
    width: 126px;
  }

  .about-themes-wrap {
    min-height: 182px;
    margin: 0;
  }

  .about-themes {
    min-height: 182px;
  }

  .about-theme {
    min-height: 32px;
    gap: 12px;
    font-size: clamp(10px, 0.5952vw, 18px);
  }

  .about-copy p {
    font-size: 16px;
  }

  .about-copy p:first-child {
    margin-left: 0;
    /* No size override either: 27px against a 30px heading is 0.9, which is no
       hierarchy at all. The clamp floor of 21px keeps the same 0.7 step it takes
       everywhere else. */
  }

  .wisdom-demo {
    min-height: 720px;
    padding: 38px 18px 48px;
  }

  .wisdom-topline > span {
    display: none;
  }

  .quote-stage {
    width: 100%;
  }

  .quote-stage blockquote {
    min-height: 3.1em;
    font-size: clamp(38px, 12vw, 58px);
  }

  .quote-stage > p {
    font-size: 18px;
  }

  .expertise-group {
    padding: 26px 0;
    grid-template-columns: 1fr;
    gap: 18px;
  }

  .expertise-group ul {
    columns: 1;
    margin-top: 5px;
  }

  .expertise-group::before {
    inset-inline: -18px;
  }

  /* No override — 27px under a 30px section heading is 0.9, and the clamp's own 21px
     floor holds the 0.7 step the rest of the scale uses. */

  .award-column {
    /* Was `35px 0 10px`, against a desktop rule that tops out at 30px — a
       phone was being given MORE room around each award than a 2560px screen.
       Scaled, with the top of the range left where the band above ends. */
    padding: clamp(22px, 5.6vw, 35px) 0 10px;
    display: block;
  }

  .award-logo {
    height: 95px;
    padding-inline: 20px;
  }

  .award-column li {
    grid-template-columns: 70px 1fr;
    padding-inline: 20px;
  }

  /* `.network-section { padding: 95px 0 }` used to sit here, for the same
     reason and with the same fault. */

  .network-intro {
    /* Was 55px, against a desktop rule of 38px — a phone was given more air
       under one line of type than a 2560px screen. With the 55px gap above it
       from the 960 band, that line of 17px text was sitting inside 110px of
       nothing, which is the single loosest thing left in this section. */
    padding-bottom: clamp(22px, 5.6vw, 38px);
  }

  .network-intro h2 {
    font-size: 45px;
  }

  .network-stats {
    grid-template-columns: 1fr;
  }

  .network-stat,
  .network-stat + .network-stat {
    /* THE SLACK GOES BELOW THE NUMBER, NOT ABOVE IT.
     *
     * The desktop rule is `justify-content: flex-end`, and there it is right:
     * measured at 1440 the content sits with 33px above and 34px below, which
     * is balance. On a phone the tile is a 16/9 rectangle 191px tall holding
     * 131px of content, and pushing all 60px of the difference to the TOP left
     * the number floating over a void — 81px of nothing above it against 23px
     * below. Anchored to the top the same slack falls at the bottom, where the
     * tile's own photograph is, and reads as picture rather than as emptiness. */
    justify-content: flex-start;
    /* Was `min-height: 240px; padding: 36px 28px` — both fixed, on the screens
       where there is least room to be fixed about. The floor now scales with
       the viewport and only reaches the old 240px once there is width for it. */
    /* THE HEIGHT IS THE CONTENT'S, NOT A RATIO'S.
     *
     * 16/9 across a full-width phone is a band 191px tall holding 131px of
     * type, and the 60px left over showed as a blank half of the photograph
     * under the caption — the tile read as a picture with a label in its
     * corner rather than as a figure. On a wide screen the same ratio is right
     * because three of them sit side by side and the ratio is what makes them
     * a row; stacked one per line there is nothing for it to be consistent
     * with, so the type decides and the tile comes out flat.
     *
     * `min-height: 0` as well, because a floor is the same mistake in a
     * different hat — see the note above the 1180 band. */
    aspect-ratio: auto;
    min-height: 0;
    padding: clamp(22px, 6vw, 36px) clamp(16px, 5vw, 28px);
    border-left: 0;
    border-bottom: 0;
  }

  .network-stat:last-child {
    border-bottom: 0;
  }

  .network-stat strong {
    /* Was a flat 72px, which is what pushed the page open: "18,000+" at 72px
       is 371px, the tile's content box was 371px, and neither could give. The
       tile measures itself (container-type: inline-size), so the number is
       sized from the tile it has to fit inside rather than from a guess. */
    font-size: clamp(30px, 17cqw, 72px);
  }


  /* HOME PHONE TYPE LADDER — 2026-08-10.
   *
   * The quote, section headings, About lead, award copy and network figures
   * already occupy distinct and comfortable roles. The split was below them:
   * nine separate label roles at 9–10px, 13px news summaries and 12px dense
   * expertise copy. Raise those roles deliberately rather than rescaling the
   * whole composition and making its large display type louder again. */
  .hero-strategy-line,
  .hero-quote__by,
  .hero-ask-launch__eyebrow,
  .news-meta,
  .text-link,
  .about-theme,
  .group-number,
  .award-column li span,
  .network-intro > a {
    font-size: var(--phone-type-label);
  }

  .hero-strategy-line {
    letter-spacing: 0.09em;
  }

  .hero-quote__by,
  .hero-ask-launch__eyebrow,
  .news-meta,
  .text-link,
  .group-number,
  .award-column li span,
  .network-intro > a {
    letter-spacing: 0.12em;
  }

  .about-theme {
    letter-spacing: 0.06em;
    line-height: 1.2;
  }

  .news-card > p {
    font-size: var(--phone-type-body);
    line-height: 1.3;
  }

  .expertise-group li {
    font-size: 14px;
    line-height: 1.3;
  }

  .network-intro > a {
    min-height: 44px;
  }

  .site-footer {
    padding-top: 65px;
  }

  .acknowledgement {
    margin-bottom: 60px;
    grid-template-columns: 1fr;
  }

  .ack-mark {
    width: 58px;
    margin: 0 auto;
  }

  .acknowledgement p {
    font-size: 25px;
  }

  .global-team-banner {
    min-height: 285px;
    margin-top: 60px;
    padding: 44px 18px;
  }

  .global-team-banner h2 {
    font-size: 40px;
  }

  .footer-bottom {
    flex-wrap: wrap;
    justify-content: flex-start;
    gap: 16px 22px;
  }

  .footer-legal {
    width: 100%;
    gap: 16px 22px;
  }

}

/* The one quotation that will not hold two lines on a phone.
 *
 * "We remove the barrier of law for business across borders." is 57 characters, and at
 * the 7.3vw the other nine take it runs to three lines on anything under 480. The rule
 * the client set is absolute — two lines, never three — so this tier steps down.
 *
 * 6.7vw is not the largest size that fits. 7vw fits, and fails at 7.3, which is one
 * rounding away; a font update or a new quotation of the same length would put it back
 * over. Two steps of slack is what makes this a rule rather than a coincidence, and the
 * 8% difference from the base is below the size a reader notices between one visit and
 * the next.
 *
 * It stops at 479 because 480 already holds two lines at the base size, and it does not
 * reach the desktop rules at all: from 768 up, one size holds all ten inside the
 * two-thirds measure.
 *
 * Measured on the rendered glyphs, not on the text. Each letter is its own span for the
 * burn-in, which costs the kerning, so the line sets wider than the same string does as
 * plain text — the earlier claim that all ten fit at ≤680 came from measuring a plain
 * string, and was wrong by exactly that difference. */
@media (max-width: 479px) {
  .hero h1.hero-quote--very-long {
    /* The floor has to stay out of the way. 6.7vw is a constant fraction of the column,
       so it holds two lines at any width on its own; a floor of 23px overrode it at 320
       and put the third line straight back. 21px is below where it can bind. */
    font-size: clamp(21px, 6.7vw, 32px);
  }
}

@media (prefers-reduced-motion: reduce) {
  html {
    scroll-behavior: auto;
  }

  ::view-transition-group(root),
  ::view-transition-group(yk-site-header),
  ::view-transition-old(root),
  ::view-transition-new(root),
  ::view-transition-old(yk-site-header),
  ::view-transition-new(yk-site-header) {
    animation: none;
  }

  *,
  *::before,
  *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    scroll-behavior: auto !important;
    transition-duration: 0.01ms !important;
  }

  .wisdom-physics {
    display: none;
  }

  .quote-letter {
    animation-delay: 0ms !important;
  }

  .hero.hero-burn-enhanced .hero-quote__by {
    opacity: 1;
    transform: none;
  }

  .about-rail-progress {
    transform: scaleY(1);
  }

  .about-theme {
    color: var(--ink);
  }

  .about-theme small {
    color: var(--gold);
  }

  .about-theme .about-theme-node {
    border-color: rgba(160, 123, 69, 0.64);
  }

  .about-theme .about-theme-node::after {
    transform: scale(0.72);
  }
}

/* ------------------------------------------------------------
   Search results

   The header search used to submit to the old site's WordPress search. That
   destination is going away, so it now matches a shipped index in the client.
   The results are styled from the same vocabulary as everything else: a tracked
   label, a serif title, hairline separators, no boxes.
   ------------------------------------------------------------ */

/* The overlay is dark: near-white type on a dark scrim. These results sit inside
   it, so they take the overlay's scheme, not the page's. Using the page's
   near-black ink here rendered the titles almost invisible. */
.search-status {
  width: var(--search-measure);
  margin: 22px auto 0;
  color: #d9b878;
  font-family: var(--sans);
  font-size: clamp(10px, 0.5952vw, 18px);
  font-weight: 700;
  letter-spacing: 0.16em;
  text-transform: uppercase;
}

.search-results {
  width: var(--search-measure);
  /* Fills its own track rather than asserting a height the track may not have. */
  max-height: 100%;
  margin: 10px auto 0;
  padding-bottom: 8px;
  overflow-y: auto;
  overscroll-behavior: contain;
}

.search-hit {
  padding: 16px 10px 16px 2px;
  display: grid;
  gap: 5px;
  border-bottom: 1px solid rgba(255, 255, 255, 0.14);
  color: inherit;
  text-decoration: none;
  transition: background-color 220ms ease;
}

.search-hit:hover,
/* `outline: none` left keyboard focus indicated only by a 1.24:1 background
   tint, identical to hover — so on the one screen reached by typing, the caret
   became invisible. The site ring, in the palette the overlay is set in. */
.search-hit:focus-visible {
  background: rgba(255, 255, 255, 0.07);
  outline: 2px solid #d9b878;
  outline-offset: 3px;
}

.search-hit:hover .search-hit__title,
.search-hit:focus-visible .search-hit__title { color: #e8c68a; }

.search-hit__kind {
  color: #d9b878;
  font-family: var(--sans);
  font-size: clamp(9px, 0.5357vw, 16.2px);
  font-weight: 700;
  letter-spacing: 0.15em;
  text-transform: uppercase;
}

.search-hit__title {
  color: #f6f3ec;
  font-family: var(--serif);
  font-size: clamp(17px, 1.09375vw, 21px);
  letter-spacing: -0.018em;
  line-height: 1.15;
  @media (max-width: 1180px) {
    font-size: clamp(17px, 1.4vw, 21px);
  }
}

.search-hit__blurb {
  color: rgba(240, 236, 228, 0.72);
  font-family: var(--serif);
  font-size: 14px;
  line-height: 1.15;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

@media (prefers-reduced-motion: reduce) {
  .search-hit { transition: none; }
}

/* ---------------------------------------------------- the minimised assistant
 *
 * Closing the window folds it into a ball in the corner rather than ending it. The
 * conversation is still there; what changed is how much room it is taking. That is
 * the honest reading of what someone means when they press × on a chat they were in
 * the middle of, and it is why this is a minimise and not a close.
 */
.ask-yk__ball {
  position: absolute;
  right: 0;
  bottom: 0;
  width: 58px;
  height: 58px;
  display: grid;
  place-items: center;
  border: 1px solid rgba(248, 244, 236, 0.16);
  border-radius: 50%;
  background: rgba(22, 24, 23, 0.96);
  box-shadow: 0 14px 38px rgba(20, 18, 15, 0.24);
  color: #fbf8f0;
  cursor: pointer;
  pointer-events: auto;
  /* Sized and placed before it is ever shown, so the dialog can be measured against
     it and land exactly on it. */
  transform-origin: 50% 50%;
}
.ask-yk__ball:hover { background: rgba(30, 32, 30, 0.98); }
.ask-yk__ball:focus-visible { outline: 2px solid var(--gold); outline-offset: 3px; }
.ask-yk__ball-mark svg {
  width: 21px;
  height: 21px;
  display: block;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.6;
  stroke-linecap: round;
}
/* Something was said while it was folded away. */
.ask-yk__ball-dot {
  position: absolute;
  top: 12px;
  right: 12px;
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--gold);
  box-shadow: 0 0 0 2px rgba(22, 24, 23, 0.96);
}

/* The fold.
 *
 * Two things were tried before this and both are worth keeping in view. Scaling the
 * panel the whole way down carries its border radius with it: a 2px corner at 0.14x
 * still measures 2px, so the panel reached the ball's size as a small rectangle and the
 * roundness had to be faked by swapping something else in. The client saw exactly that
 * — 它缩到最小，然后一个圆蹦出来. Animating the panel's own width and height fixed the
 * shape and broke the motion: the whole conversation was inside it, re-laid-out on
 * every frame, over a page already running a generative canvas.
 *
 * So the journey is split at 0.86 of the panel's size. Below that an empty ghost
 * carries it — `contain: strict`, nothing inside to reconsider — and its radius grows
 * into a real circle. Above it the panel carries itself on a transform: no relayout,
 * and the radius never travels far enough to matter. The two boxes coincide exactly,
 * because the panel scales about the very corner the ball sits in.
 *
 * The timing of the contents lives in ask-yk-demo.js, on the same timeline as the
 * shape: going down the words leave first and the box is already closing behind them;
 * coming back they are released at the hand-off, so they rise while the box is still
 * growing rather than appearing in one frame after it has stopped.
 */

/* Anyone who has asked not to be moved gets the exchange without the journey. */
@media (prefers-reduced-motion: reduce) {
  .ask-yk__ball .ask-yk__ball-mark { animation: none; }
}

@media (max-width: 640px) {
  .ask-yk__ball { width: 52px; height: 52px; }
}

/* The travelling shell. Empty, and told so — `contain: strict` lets the browser skip
   everything inside it, which is the whole reason the fold is smooth now. */
.ask-yk__ghost {
  position: fixed;
  z-index: 30;
  contain: strict;
  pointer-events: none;
  display: grid;
  place-items: center;
  /* It starts as the panel's own surface and ends as the ball's — colour, edge and
     shadow travel with the shape. Landing as a cream rounded square and being swapped
     for a dark circle is what made the old fold read as a pop. */
  border: 1px solid rgba(23, 24, 21, 0.2);
  background: #fbfaf6;
  box-shadow: 0 22px 66px rgba(15, 14, 11, 0.23);
}

/* The roundel, surfacing inside the box as it closes on it. */
.ask-yk__ghost-mark {
  width: 21px;
  height: 21px;
  display: block;
  opacity: 0;
  color: #fbf8f0;
}
.ask-yk__ghost-mark svg {
  width: 100%;
  height: 100%;
  display: block;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.6;
  stroke-linecap: round;
}

/* The corner that moves. Anchored bottom-right, so this is the top-left one — and it
   is a real target rather than a hairline, because it is dragged on an iPad too. */
.ask-yk__grip {
  position: absolute;
  z-index: 22;
  pointer-events: auto;
  top: 0;
  left: 0;
  width: 22px;
  height: 22px;
  cursor: nwse-resize;
  touch-action: none;
}
.ask-yk__grip::before {
  content: "";
  position: absolute;
  top: 7px;
  left: 7px;
  width: 9px;
  height: 9px;
  border-top: 1.5px solid rgba(23, 24, 21, 0.16);
  border-left: 1.5px solid rgba(23, 24, 21, 0.16);
  border-radius: 2px 0 0 0;
  transition: border-color 160ms ease;
}
.ask-yk__grip:hover::before { border-color: var(--gold); }
.ask-yk__grip:focus-visible { outline: 2px solid var(--gold); outline-offset: -2px; }
/* Nothing inside reflows while the corner is being dragged. */
.ask-yk__dialog.is-resizing { user-select: none; }
.ask-yk__dialog.is-resizing .ask-yk__body { pointer-events: none; }

/* The roundel in the ball. Cream on the dark disc, at the size the mark was drawn to
   read at — the emblem is a solid form, so it wants room rather than weight. */
.ask-yk__ball-mark svg {
  width: 26px;
  height: 26px;
  display: block;
  fill: #f3ece0;
  stroke: none;
}
.ask-yk__ball:hover .ask-yk__ball-mark svg { fill: #fbf8f0; }

/* SHARED PHONE CHROME — 2026-08-10.
 *
 * The public pages now use one phone type ladder, but the persistent chrome still
 * carried its old micro-copy: 8–11px assistant labels, a 9px Cookie eyebrow and a
 * 10px footer. This block raises only those constrained interface roles. The panel
 * also gets the height that the larger copy needs on a 320×568 screen; otherwise the
 * one button that starts it would remain below the scroll origin. */
@media (max-width: 680px) {
  .footer-bottom {
    font-size: var(--phone-type-label);
    line-height: 1.25;
    letter-spacing: 0.1em;
  }

  .footer-legal {
    row-gap: 8px;
  }

  .cookie-consent__glass {
    padding: 16px;
    border-radius: 10px;
  }

  .cookie-consent__eyebrow {
    margin-bottom: 7px;
    font-size: var(--phone-type-label);
    letter-spacing: 0.12em;
  }

  .cookie-consent h2 {
    font-size: 22px;
    line-height: 1.08;
  }

  .cookie-consent__glass > p:not(.cookie-consent__eyebrow) {
    margin: 9px 0 15px;
    font-size: 13px;
    line-height: 1.32;
  }

  .cookie-consent__actions button {
    min-height: 44px;
    padding-inline: 14px;
    font-size: 13px;
    line-height: 1.15;
  }

  .ask-yk {
    right: max(10px, env(safe-area-inset-right));
    bottom: max(10px, env(safe-area-inset-bottom));
  }

  /* The mobile navigation and search are modal surfaces. Leaving a second floating
     trigger above either one created two competing focus targets and let the assistant
     intercept taps meant for the menu. It returns as soon as the active surface closes. */
  body.menu-open .ask-yk,
  body.search-open .ask-yk {
    visibility: hidden;
    pointer-events: none;
  }

  .ask-yk__dialog {
    width: min(420px, calc(100vw - 20px));
    height: min(640px, calc(100svh - 20px));
    max-height: calc(100svh - 20px);
    --ask-yk-header-h: 56px;
  }

  .ask-yk__header {
    min-height: var(--ask-yk-header-h);
    padding: 6px 6px 6px 14px;
  }

  .ask-yk__new {
    min-height: 44px;
    font-size: var(--phone-type-label);
    letter-spacing: 0.08em;
  }

  .ask-yk__close {
    width: 44px;
    height: 44px;
  }

  .ask-yk__close svg {
    width: 15px;
    height: 15px;
  }

  .ask-yk__body {
    padding: 14px;
  }

  .ask-yk__intro {
    margin-bottom: 14px;
    font-size: 14px;
    line-height: 1.35;
  }

  .ask-yk__message {
    padding: 10px 11px;
    font-size: 14px;
    line-height: 1.35;
  }

  .ask-yk__message span,
  .ask-yk__lead-head span {
    font-size: var(--phone-type-label);
    letter-spacing: 0.1em;
  }

  .ask-yk__message--response a,
  .ask-yk__sources a {
    min-height: 24px;
    display: flex;
    align-items: center;
    font-size: var(--phone-type-label);
    line-height: 1.3;
  }

  .ask-yk__handoff {
    min-height: 44px;
    font-size: 13px;
  }

  .ask-yk__suggestions button {
    min-height: 36px;
    padding: 7px 9px;
    font-size: var(--phone-type-label);
    line-height: 1.2;
  }

  .ask-yk__form {
    min-height: 64px;
    padding: 8px 8px 8px 14px;
    grid-template-columns: minmax(0, 1fr) 44px;
  }

  .ask-yk__form textarea {
    min-height: 44px;
    font-size: var(--phone-type-control);
    line-height: 1.25;
  }

  .ask-yk__form button {
    width: 44px;
    height: 44px;
  }

  .ask-yk__lead {
    inset: var(--ask-yk-header-h) 0 0;
    padding: 14px;
  }

  .ask-yk__lead > p {
    font-size: 13px;
    line-height: 1.35;
  }

  .ask-yk__lead label > span {
    font-size: var(--phone-type-label);
  }

  .ask-yk__lead input {
    min-height: 44px;
    font-size: var(--phone-type-control);
  }

  .ask-yk__lead-submit {
    min-height: 44px;
    font-size: 13px;
  }

  .ask-yk__disclaimer {
    padding: 0 14px 12px;
    color: #65635d;
    font-size: var(--phone-type-label);
    line-height: 1.3;
    letter-spacing: 0.025em;
  }

  .ask-yk__terms {
    padding: 12px;
  }

  .ask-yk__terms-card {
    padding: 16px;
  }

  .ask-yk__terms-eyebrow {
    margin-bottom: 7px;
    font-size: var(--phone-type-label);
    letter-spacing: 0.11em;
  }

  .ask-yk__terms h3 {
    font-size: 24px;
    line-height: 1.06;
  }

  .ask-yk__terms-card > p:not(.ask-yk__terms-eyebrow, .ask-yk__terms-status),
  .ask-yk__terms-check {
    font-size: var(--phone-type-label);
    line-height: 1.3;
  }

  .ask-yk__terms-card > p:not(.ask-yk__terms-eyebrow, .ask-yk__terms-status) {
    margin: 11px 0 14px;
  }

  .ask-yk__terms-check {
    grid-template-columns: 19px minmax(0, 1fr);
  }

  .ask-yk__terms-check input {
    width: 18px;
    height: 18px;
  }

  .ask-yk__terms-start,
  .ask-yk__terms-cookie {
    min-height: 44px;
    margin-top: 14px;
    font-size: 13px;
  }

  .ask-yk__terms-start {
    bottom: -16px;
  }

  .ask-yk__terms-privacy {
    /* The closed panel is pre-warmed at scale(.972); 26px still resolves above the
       24px target floor during that invisible preparation frame. */
    min-height: 26px;
    margin-top: 8px;
    display: inline-flex;
    align-items: center;
    font-size: var(--phone-type-label);
  }

  .ask-yk__terms-status {
    font-size: var(--phone-type-label);
    line-height: 1.3;
  }

  /* Keep the full 44px touch target, but stop the launcher behaving like an opaque
     black sticker over the page. Its exact skin is read by ask-yk-demo.js, so the
     desktop-to-phone fold still hands over without a colour or shadow pop. */
  .ask-yk__ball {
    width: 44px;
    height: 44px;
    border-color: rgba(82, 70, 56, 0.34);
    background: rgba(251, 250, 246, 0.82);
    box-shadow: 0 6px 18px rgba(20, 18, 15, 0.14);
    color: #754834;
    backdrop-filter: blur(4px);
    -webkit-backdrop-filter: blur(4px);
  }

  .ask-yk__ball:hover {
    background: rgba(251, 250, 246, 0.96);
  }

  .ask-yk__ball-mark svg {
    width: 21px;
    height: 21px;
    fill: #754834;
  }

  .ask-yk__ball:hover .ask-yk__ball-mark svg {
    fill: #5f3829;
  }

  .ask-yk__ball-dot {
    top: 7px;
    right: 7px;
    width: 7px;
    height: 7px;
    box-shadow: 0 0 0 2px rgba(251, 250, 246, 0.92);
  }
}

/* Homepage-only refinements: keep the closing network sequence compact without
   turning it into a small island, and strengthen the Expertise service labels. */
.expertise-group li {
  color: rgba(255, 255, 255, 0.84);
  font-size: clamp(15px, 0.9375vw, 18px);
  line-height: 1.25;
}

.network-section {
  padding-top: clamp(22px, 1.66667vw, 32px);
  padding-bottom: clamp(24px, 1.875vw, 36px);
  color: var(--ink);
  background: var(--paper);
}

.network-intro,
.network-stats {
  width: 75%;
  margin-inline: auto;
}

.network-intro {
  padding-bottom: 6px;
  border-bottom-width: 1px;
  border-bottom-color: rgba(122, 90, 44, 0.32);
}

.network-intro > a {
  gap: 13.5px;
  color: var(--quote-warm);
  font-size: clamp(10px, 0.4464vw, 13.5px);
}

.network-intro .link-arrow {
  width: 12.75px;
  height: 12.75px;
  margin-left: 3px;
}

.network-stats {
  gap: 12px;
  padding-top: 4px;
}

.network-stat {
  aspect-ratio: 4 / 1;
  min-height: 0;
  padding: clamp(12px, 1.1vw, 18px) 28.5px;
  justify-content: center;
}

.network-stat + .network-stat {
  padding-left: 28.5px;
}

.network-stat:nth-child(1) {
  background-image: url("assets/live-stat-home-crop-v6.jpg");
}

.network-stat:nth-child(2) {
  background-image: url("assets/live-stat-case-studies-crop-v6.jpg");
}

.network-stat:nth-child(3) {
  background-image: url("assets/live-stat-insights-crop-v6.jpg");
}

.network-stat::before {
  background: rgba(247, 242, 234, 0.08);
  -webkit-backdrop-filter: blur(1.8px) saturate(0.94);
  backdrop-filter: blur(1.8px) saturate(0.94);
}

.network-stat::after {
  border-width: 1px;
  border-color: rgba(247, 226, 183, 0.4);
}

.network-stat strong {
  color: #f2d497;
  font-size: clamp(25.5px, 22cqw, 58px);
  text-shadow: 0 1px 10px rgba(16, 20, 39, 0.28);
}

.network-stat span {
  margin-top: 8px;
  color: rgba(255, 255, 255, 0.84);
  font-size: 9px;
  text-shadow: 0 1px 6px rgba(16, 20, 39, 0.34);
}

/* The compact footer, and it is compact on EVERY page.
 *
 * These rules were once written `body:has(#main-content) .site-footer …`.
 * `#main-content` is rendered by exactly one route — routes/home.tsx — so that
 * prefix silently meant "home only": every other page kept the older, much
 * larger footer (25px acknowledgement and a 285px band at phone width, against
 * 16px and 120px here). The footer is one shared component, SiteFooter in
 * components/site-chrome.tsx, reached through the routes/site.tsx layout, and
 * one component deserves one appearance.
 *
 * So there is no page gate here, and nothing below may reintroduce one. The
 * block above (`.site-footer`, `.acknowledgement`, `.global-team-banner` near
 * the top of this file) still owns the structure — grid, centring, the band's
 * photograph; this block owns the scale. Tune the scale here and every page
 * moves together. */
.site-footer {
  --footer-statement-size: clamp(16px, 1.04167vw, 20px);
  padding-top: clamp(24px, 1.875vw, 36px);
}

.site-footer .acknowledgement {
  width: 75%;
  max-width: clamp(488.25px, 41.40623vw, 795px);
  margin-bottom: clamp(20px, 1.25vw, 24px);
  grid-template-columns: 32px minmax(0, 1fr);
  gap: clamp(12px, 0.72917vw, 14px);
}

.site-footer .ack-mark {
  width: 32px;
}

.site-footer .acknowledgement p {
  font-family: var(--serif);
  font-size: var(--footer-statement-size);
  font-style: italic;
  font-weight: 400;
  letter-spacing: -0.02em;
  line-height: 1.15;
}

.site-footer .global-team-banner {
  width: 100%;
  min-height: clamp(72px, 5.72917vw, 110px);
  margin: clamp(20px, 1.25vw, 24px) auto 0;
  padding: clamp(16px, 1.04167vw, 20px) var(--band-inset);
}

.site-footer .global-team-banner::before {
  content: none;
}

.site-footer .global-team-banner h2 {
  max-width: clamp(370px, 31.25vw, 600px);
  font-family: var(--serif);
  font-size: var(--footer-statement-size);
  font-weight: 400;
  letter-spacing: -0.04em;
  line-height: 1.05;
  text-shadow: 0 1px 8px rgba(0, 0, 0, 0.32);
}

@media (max-width: 1180px) {
  .network-section {
    padding-top: clamp(18px, 2.2vw, 26px);
    padding-bottom: clamp(20px, 2.4vw, 28px);
  }

  .network-stat {
    padding: clamp(10px, 1.5vw, 16px) clamp(15px, 2.25vw, 28.5px);
  }

  .network-stat + .network-stat {
    padding-left: clamp(15px, 2.25vw, 28.5px);
  }

  .site-footer {
    padding-top: 32px;
  }

  .site-footer .acknowledgement {
    width: calc(75vw - 42px);
    max-width: 795px;
    margin-bottom: 24px;
    gap: 14px;
  }

  .site-footer .acknowledgement p {
    font-size: var(--footer-statement-size);
  }

  .site-footer .global-team-banner {
    min-height: 115px;
    margin-top: 24px;
    padding-top: 20px;
    padding-bottom: 20px;
  }

  .site-footer .global-team-banner h2 {
    max-width: 600px;
    font-size: var(--footer-statement-size);
  }
}

@media (max-width: 960px) {
  .network-intro,
  .network-stats {
    width: 100%;
  }

  .network-stat {
    aspect-ratio: 5 / 1;
    min-height: 0;
  }

  .site-footer .acknowledgement {
    width: var(--page);
    max-width: none;
  }
}

@media (max-width: 680px) {
  .expertise-group li {
    font-size: 16px;
    line-height: 1.3;
  }

  .network-intro {
    padding-bottom: 6px;
  }

  .network-intro > a {
    min-height: 44px;
    font-size: var(--phone-type-label);
  }

  .network-stat,
  .network-stat + .network-stat {
    aspect-ratio: 3.6 / 1;
    padding: clamp(10px, 2.8vw, 14px) clamp(12px, 3.75vw, 21px);
    justify-content: center;
  }

  .network-stat strong {
    font-size: clamp(22.5px, 12.75cqw, 54px);
  }

  .site-footer {
    --footer-statement-size: 16px;
    padding-top: 24px;
  }

  .site-footer .acknowledgement {
    width: var(--page);
    margin-bottom: 24px;
    grid-template-columns: 1fr;
    gap: 14px;
  }

  .site-footer .ack-mark {
    width: 28px;
  }

  .site-footer .acknowledgement p {
    font-size: var(--footer-statement-size);
  }

  .site-footer .global-team-banner {
    min-height: 120px;
    margin-top: 24px;
    padding: 22px 18px;
  }

  .site-footer .global-team-banner h2 {
    font-size: var(--footer-statement-size);
  }
}

/* THE THREE FIGURES, WHERE THE SENTENCE THAT NEEDS THEM IS. They were three
   photographic tiles in a band of their own at the foot of the page — one card
   per number, each with its own artwork — and the paragraph directly above them
   already said "more than 18,000 lawyers" in prose. The client's instruction was
   to fold the data into the About copy and drop the tiles; the numbers now sit
   under the sentence they are evidence for.

   No artwork, no fixed ratio, no `overflow: hidden`: this is type on the page's
   own paper, so a longer label wraps instead of being cropped — which is the
   defect the tiles had and the reason they could not be edited safely. */
.about-figures {
  /* A rule above AND below. This block sits between two paragraphs, and with a
     top margin alone the paragraph after it started on the line under the
     labels — the numbers read as a caption on somebody else's sentence. The
     bottom margin matches the paragraph rhythm around it. */
  margin: clamp(26px, 2.2vw, 38px) 0 clamp(28px, 2.4vw, 40px);
  padding-top: clamp(20px, 1.7vw, 28px);
  padding-bottom: clamp(22px, 1.9vw, 32px);
  border-bottom: 1px solid rgba(28, 26, 24, 0.16);
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: clamp(18px, 2vw, 34px);
  border-top: 1px solid rgba(28, 26, 24, 0.16);
}

.about-figures > div {
  min-width: 0;
}

.about-figures dt {
  color: var(--ink, #1b1c19);
  font-family: var(--serif);
  font-size: clamp(30px, 2.5vw, 44px);
  font-weight: 400;
  letter-spacing: -0.03em;
  line-height: 1;
  font-variant-numeric: tabular-nums;
}

.about-figures dd {
  margin: 10px 0 0;
  color: var(--muted, #625d55);
  font-family: var(--sans);
  font-size: clamp(12px, 0.7143vw, 14px);
  font-weight: 700;
  letter-spacing: 0.13em;
  line-height: 1.3;
  text-transform: uppercase;
  text-wrap: pretty;
}

@media (max-width: 680px) {
  .about-figures {
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: 12px;
  }

  .about-figures dt {
    font-size: 26px;
  }

  .about-figures dd {
    font-size: 11px;
    letter-spacing: 0.08em;
  }
}

/* ─────────────────────────────────────────────────────── the footer ────── */

/* ONE GROUND, ONE SPINE. See the note on SiteFooter in components/site-chrome.tsx
   for what this replaced and why. Everything below is scoped to `.footer-inner`
   so the older `.acknowledgement` and `.global-team-banner` rules further up
   this file cannot reach it — they are for the frozen reference templates. */
.site-footer:has(.footer-inner) {
  padding: 0;
  position: relative;
  isolation: isolate;
  overflow: hidden;
  /* NOT A FLAT BLACK, AND NOT NOISE EITHER. The first version of this plane
     used the site's `--grain` — fractal noise — and the client's reading of it
     was exact: random has no unit, so nothing is pieced together, and on a dark
     ground the parts that do show read as dirt rather than as a surface.

     What is here instead is the mark. `assets/yk-mark.svg` is three faces
     meeting at a centre — an isometric cube — and a rhombille tiling is that
     cube repeated. So the texture is not decoration borrowed from somewhere;
     it is the logo at wallpaper scale, lit the same way: top face lightest,
     left face faint, right face in shade.

     The tile holds a whole number of cubes in both directions (width √3·R,
     height 3R, alternate rows shifted half a width), so the repeat has no seam.
     R = 52 and the face opacities are the two numbers that decide how loud it
     is; at half this size and full contrast the pattern won the page off the
     sentence, which is the wrong way round for a footer. They have come down
     twice: to 45% when the client asked for less pattern and more black, then
     to 32% when the ground went lighter again. THE SECOND CUT IS NOT A CHANGE
     OF MIND — the faces are alpha, so a lighter ground carries them further,
     and holding them steady would have made the pattern louder than the
     strength that was already signed off.
     Generated by the tiling in HANDOFF d95 — edit R and the fill-opacities
     together, not the path data.
     
     Under it: a warm graphite rather than a neutral black. #383430 is the third
     value this plane has had — #191a1d, then #101113 when the client asked for
     blacker, then this when the same client, looking at the result against the
     page, asked for lighter. That is not indecision: near-black is what made the
     footer read as a separate object, and the ramp above could hide the line but
     not the gulf. Lighter and warmer is the setting where the footer belongs to
     the paper it follows. The fall to #2b2824 keeps a large area from looking
     printed. */
  /* A SHORT BAND, NOT A LONG FADE. There was a 150px alpha ramp here that let
     the ink rise out of whatever paper sat above it, so the seam disappeared
     entirely. It worked, and the client did not want it: a fade that deep reads
     as an effect, and it made an already tall footer taller.

     What replaced it is the other answer to the same complaint. A dark band
     reads as a separate object when it is big enough to be a section; at a
     third of the viewport it reads as the bottom of the page. So the ground is
     flat again and the height came down instead — see .footer-inner below,
     where the numbers actually live.

     ONE COLOUR, AND IT IS ONE DECLARATION. The client's reading — `背景不是单一
     颜色的…看着很怪，不高级` — was measurable. Scanning a horizontal line across
     the footer, the ground wandered 68→78 left to right and 78→60 top to
     bottom. Two things were doing it: an aerial photograph washed over the
     plane at 7.5% in `screen`, which is a blotch with no shape and lifted the
     left side ten to fourteen values more than the right, and a 178deg fall —
     fourteen values top to bottom, and tilted two degrees off vertical, so even
     the fall was not level.

     A blur was asked about and measured before being rejected: at `blur(60px)`
     the wander was still 67→74 and 74→59. **Blurring an uneven thing spreads
     the unevenness, it does not remove it.** Deleting it does.

     GOLD IS AN ACCENT, NOT A BODY COLOUR — and this plane spent a round
     proving it. `黑底金文` produced exactly that: the statement, the button, the
     acknowledgement, the legal row and the lattice all in #dfbd7e at different
     alphas. Everything above this footer is paper, near-black ink, and gold used
     sparingly — on a year label, on the mark. Setting gold as the running colour
     inverts the site's own logic, and the word for the result was 丑陋.

     So: a warm ink ground and paper-coloured type, with gold left to do the two
     jobs it does everywhere else — the eyebrow that names the firm, and the fill
     that crosses the button on hover. #22201d rather than #000 because a warm
     page deserves a warm dark, and #faf7f0 rather than #fff because nothing on
     this site is pure white. */
  background-color: #22201d;
  background-image: none;
  color: #efece4;
}

/* THE LATTICE IS GONE, and it is worth saying why rather than leaving a hole.
   It was the mark's own isometric cube tiled across the plane — the geometry was
   right and the placement was wrong. Every texture on this site is paper grain:
   felt, never seen. A drawn pattern across a dark band is the one visible
   texture in the whole design, and next to the restraint above it read as
   decoration. The plane carries type and a rule now, which is what the rest of
   the site carries. */

/* THE MARK'S CUBE, DRAWN AS EDGES RATHER THAN FACES. Four versions of this
   tiling were photographed on the live page before one was chosen (d95); the
   client has now come back for the one that was set aside — hairlines only, no
   shaded faces, on a smaller cube. R = 26, 1px stroke, drawn in the gold rather
   than in white: on a black ground white hairlines read as a wireframe and gold
   ones read as foil. 16% rather than 8.5% because gold is darker than white and
   the ground is darker than it was, so the old number would have vanished.

   Same rhombille tiling and the same seamless repeat as the faces version, so
   only the drawing changed. `√3·R` by `3R` means every size in this family
   keeps the ratio √3⁄3, which is why the phone override below can scale the
   tile without bending the cubes out of isometric.

   The tile lives on this pseudo-element rather than in the ground because it
   once needed a mask of its own, and it stays here: one layer, one job, and the
   ground is free to be a single flat declaration.

   This pseudo-element was once a 16% paper haze across the top 60–110px. A lit
   top edge is the one thing a dark band does not need — it is what made this
   footer read as an object laid on the page. It must not come back. */


.footer-inner {
  width: var(--page);
  margin: 0 auto;
  /* THE HEIGHT IS THE ANSWER NOW, so it is worth writing down what it was.
     Measured at 1440×900 with the ramp: 563px, 63% of the viewport. A dark area
     that size IS a section, and a section at the bottom of a page reads as a
     separate thing however its top edge is handled. Every number below came
     down together rather than one being singled out — trimming only the padding
     leaves the interior spacing looking stretched around the same content. */
  padding: clamp(52px, 4.4vw, 78px) 0 clamp(22px, 1.7vw, 30px);
  /* TWO COLUMNS ABOVE 900px, because one was not spacious, it was unfinished.
     With the statement capped at 20ch and everything stacked on the left, half
     of a 1440px screen was empty and the plane read as a page that had run out
     rather than one that had landed. The acknowledgement takes the right and
     sits on the statement's last line, so the two things the firm says here
     face each other instead of queueing. */
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  column-gap: clamp(40px, 5vw, 96px);
  align-items: end;
}

@media (min-width: 900px) {
  .footer-inner {
    grid-template-columns: minmax(0, 1.15fr) minmax(0, 1fr);
  }

  /* Rows shift down by one for the eyebrow. Named explicitly for all four:
     the pseudo-element is auto-placed, and auto-placement puts it after anything
     that carries a row of its own — it landed under the legal line. */
  .footer-statement { grid-column: 1; grid-row: 2; }

  /* `justify-self`, because a grid item fills its column: without it the button
     stretched to 890px and stopped being a button. */
  .footer-action {
    grid-column: 1;
    grid-row: 3;
    justify-self: start;
  }

  .footer-acknowledgement {
    grid-column: 2;
    grid-row: 2 / 4;
    /* Hangs from the rule rather than sitting on the statement's last line: the
       two now share a top edge, which is what makes them read as one band. */
    align-self: start;
    margin-top: 0;
    margin-bottom: 0;
  }

  .site-footer:has(.footer-inner) .footer-bottom {
    grid-column: 1 / -1;
    grid-row: 4;
  }
}


/* THE EYEBROW IS THE RULE. One grid row spanning both columns, so the statement
   and the acknowledgement hang from a single line instead of floating at their
   own heights — which is how the awards table and the editorial index are built,
   and the reason those read as composed and this did not.

   A rule of its own rather than nested inside .footer-inner: the nested form
   rendered its text and dropped its border, and a line that is the whole point
   of the composition is not worth debugging a nesting edge case for. */
.footer-inner::before {
  content: "YK Law Australia";
  grid-column: 1 / -1;
  grid-row: 1;
  padding-bottom: clamp(12px, 1.1vw, 16px);
  margin-bottom: clamp(26px, 2.4vw, 38px);
  border-bottom: 1px solid rgba(239, 236, 228, 0.2);
  color: #dfbd7e;
  font-family: var(--sans);
  font-size: 10.5px;
  font-weight: 700;
  letter-spacing: 0.24em;
  text-transform: uppercase;
}

.footer-statement {
  /* 24ch and a third off the size. At 62px this was a billboard with a page
     underneath it; the sentence is the firm's voice, not its masthead, and it
     reads as a sentence at 36. */
  max-width: 24ch;
  margin: 0;
  color: #faf7f0;
  font-family: var(--serif);
  font-size: clamp(23px, 2.05vw, 36px);
  font-weight: 400;
  letter-spacing: -0.014em;
  line-height: 1.26;
  text-wrap: balance;
}

/* The one thing to do, and it is the only bright object on the plane. Paper on
   ink at rest, inverting to ink on paper as the fill crosses it — the same
   gesture as the enquiry button, read the other way round because here the
   ground is already dark. */
.footer-action {
  min-width: 232px;
  min-height: 52px;
  margin-top: clamp(22px, 2vw, 34px);
  padding: 14px 18px 14px 22px;
  position: relative;
  isolation: isolate;
  overflow: hidden;
  display: inline-flex;
  align-items: center;
  justify-content: space-between;
  gap: clamp(22px, 2vw, 36px);
  border: 1px solid rgba(239, 236, 228, 0.32);
  color: #faf7f0;
  text-decoration: none;
  font-family: var(--sans);
  font-size: 12px;
  font-weight: 700;
  letter-spacing: 0.15em;
  line-height: 1;
  text-transform: uppercase;
  transition: color 260ms ease, border-color 260ms ease;
}

.footer-action__fill {
  position: absolute;
  z-index: -1;
  inset: 0;
  background: #dfbd7e;
  transform: scaleX(0);
  transform-origin: 100% 50%;
  transition: transform 520ms cubic-bezier(0.22, 1, 0.36, 1);
}

.footer-action__arrow {
  width: 18px;
  height: 18px;
  flex: 0 0 auto;
  fill: none;
  stroke: currentColor;
  stroke-linecap: square;
  stroke-linejoin: miter;
  stroke-width: 1.35;
  transition: transform 380ms cubic-bezier(0.22, 1, 0.36, 1);
}

.footer-action:hover,
.footer-action:focus-visible {
  /* The fill is gold, so the label becomes the ground rather than paper. */
  color: #241f1a;
  border-color: #dfbd7e;
}

.footer-action:hover .footer-action__fill,
.footer-action:focus-visible .footer-action__fill {
  transform: scaleX(1);
  transform-origin: 0 50%;
}

.footer-action:hover .footer-action__arrow,
.footer-action:focus-visible .footer-action__arrow {
  transform: translateX(4px);
}

.footer-action:focus-visible {
  outline: 2px solid #f7f4ec;
  outline-offset: 4px;
}

/* Moved down the page, NOT made smaller. It was the lightest thing in the old
   footer, which is the wrong way to carry this sentence. */
.footer-acknowledgement {
  max-width: 62ch;
  margin: clamp(30px, 2.8vw, 48px) 0 0;
  padding-left: 40px;
  position: relative;
  color: rgba(239, 236, 228, 0.6);
  font-family: var(--serif);
  font-size: clamp(14px, 0.95vw, 18px);
  font-style: italic;
  line-height: 1.55;
  text-wrap: pretty;
}

.footer-ack-mark {
  position: absolute;
  top: 2px;
  left: 0;
  width: 24px;
  height: 24px;
  display: block;
}

.footer-ack-mark svg {
  width: 100%;
  height: 100%;
  fill: none;
  stroke: rgba(190, 152, 96, 0.85);
  stroke-width: 1.2;
  stroke-linecap: round;
  stroke-linejoin: round;
}

.site-footer:has(.footer-inner) .footer-bottom {
  width: auto;
  margin: clamp(26px, 2.3vw, 40px) 0 0;
  padding-top: clamp(14px, 1.1vw, 20px);
  border-top: 1px solid rgba(239, 236, 228, 0.14);
  /* 0.55 WAS SET AGAINST A NEAR-BLACK GROUND AND DID NOT SURVIVE THE LIGHTER
     ONE. Composited — which is the only honest way to read an rgba text colour —
     0.55 over #383430 is 4.0:1, under the 4.5 AA asks of text this size. It was
     5.2:1 on #101113, so the row did not change; the plane under it did. At 0.74
     it is back to 5.6:1 and still visibly quieter than the links beside it. */
  color: rgba(239, 236, 228, 0.55);
}

.site-footer:has(.footer-inner) .footer-legal a,
.site-footer:has(.footer-inner) .footer-cookie-settings {
  color: rgba(239, 236, 228, 0.82);
}

.site-footer:has(.footer-inner) .footer-legal a:hover,
.site-footer:has(.footer-inner) .footer-cookie-settings:hover {
  color: #faf7f0;
}

@media (max-width: 680px) {
  .footer-statement {
    max-width: none;
    font-size: 28px;
  }

  .footer-action {
    width: 100%;
    min-width: 0;
  }

  .footer-acknowledgement {
    padding-left: 32px;
    font-size: 14px;
  }
}

@media (prefers-reduced-motion: reduce) {
  .footer-action,
  .footer-action__fill,
  .footer-action__arrow {
    transition: none;
  }
}
