/* ==========================================================
   ht-law / tokens.css
   Layer 3. The only file in this project that may contain a
   literal colour, font name or pixel value.

   Four documented exceptions live outside this file, because
   none of them can read a custom property. They are written out
   here in words rather than in placeholder syntax, so that a
   find and replace fill cannot rewrite this comment.

     1. meta theme-color        carries the brand colour as a
                                placeholder, in every page head
     2. site.webmanifest        the same, twice
     3. generated brand assets  favicon, OG image, icons. Built
                                from src/ masters. Regenerate
                                whenever --accent moves.
     4. media query conditions  in layout.css. CSS does not allow
                                a custom property inside a media
                                feature, and there is no build
                                step to substitute one.

   md/README.md carries the full reasoning.
   ========================================================== */

/* ─ face ────────────────────────────────────────────────────
   Figtree, wght 300 to 900, served by Google Fonts. The @font-face
   comes from their stylesheet, which every page head requests with
   media="print" so it never blocks the first paint, then promotes
   with js/modules/fonts.js.

   Nothing about the face is declared here, so this file no longer
   decides where the font comes from, only what it is called. The
   name below has to match the family Google serves.

   Two consequences, both recorded in md/README.md. The CSP in
   _headers has to allow two Google origins. And Google's Figtree
   subsets do not carry U+2192, so the button arrows are inline SVG
   rather than a font glyph.
   ────────────────────────────────────────────────────────── */

:root {

  /* ─ colour ─────────────────────────────────────────────── */

  --ink:            #0A0A0A;
  --paper:          #FFFFFF;
  --surface:        #F7F7F7;
  --muted:          #4A4A4A;
  --accent:         #162737;
  --accent-ink:     #FFFFFF;

  /* The firm's secondary brand colour. Declared so the value lives
     with the rest of the palette, and deliberately consumed by
     nothing: every component reads --accent, and giving one of them
     a second hue is a composition decision, not a token swap. */
  --accent-2:       #9E015E;
  --rule:           #E5E5E5;

  /* extension: three hairline greys and a hover accent.

     --accent-hover is the firm's secondary colour rather than a
     lighter --accent. It was derived from --accent in the source,
     lifting OKLCH lightness and chroma at a fixed hue, and the
     @supports block that computed it has been removed with it:
     a relative-colour override would have silently won over this
     literal in every browser that supports the syntax, which is
     most of them, and the hover would have stayed the accent.

     This is now a second hue, so it no longer follows --accent.
     Changing the accent leaves this untouched. White on #9E015E
     is 8.0:1, which clears AA for the primary button label and
     for the prose link and form error colours below. */
  --accent-hover:   var(--accent-2);
  --rule-strong:    #D4D4D4;
  --rule-bold:      #BFBFBF;
  --rule-field:     #949494;

  /* The secondary button's outline, so a button looks like a button
     before anyone hovers it. 3.03:1 on paper, where --rule-bold was
     1.84:1 and left the control almost invisible. Kept separate from
     the hairline greys because a control and a divider should not be
     forced to change together. */
  --btn-line:       #949494;

  /* extension: text on the accent field. Nine alpha steps in the
     source, consolidated to five. --accent-ink-dim replaces the
     0.50 and 0.45 steps, both of which failed AA at 12px.

     These are alphas, so the contrast they achieve depends on how
     dark --accent is. They are safe down to a relative luminance
     of about 0.06, which covers a deep navy, green, red or plum.
     A mid-tone accent needs them raised. md/README.md carries the
     table and the ceiling. */
  --accent-ink-strong: rgba(255, 255, 255, 0.80);
  --accent-ink-body:   rgba(255, 255, 255, 0.75);
  --accent-ink-muted:  rgba(255, 255, 255, 0.65);
  --accent-ink-soft:   rgba(255, 255, 255, 0.62);
  --accent-ink-dim:    rgba(255, 255, 255, 0.58);

  /* extension: surfaces and lines on the accent field */
  --accent-fill-hover: rgba(255, 255, 255, 0.88);
  --accent-fill-press: rgba(255, 255, 255, 0.75);
  --accent-line:       rgba(255, 255, 255, 0.70);
  --accent-line-press: rgba(255, 255, 255, 0.60);
  --accent-rule:       rgba(255, 255, 255, 0.15);
  --accent-rule-soft:  rgba(255, 255, 255, 0.12);
  --accent-btn-fill:   rgba(255, 255, 255, 0.10);

  /* The nav and drawer shadows are the accent at 35%, so they
     read as the header's own colour deepening rather than a grey
     smudge. Derived, so changing --accent alone is enough. On the
     original navy this resolves to exactly the rgba(2, 47, 119,
     0.35) it replaces. */
  --accent-shadow:     color-mix(in srgb, var(--accent) 35%, transparent);
  --ink-line-press:    rgba(0, 0, 0, 0.50);

  /* placeholder text sits at 0.76 of --muted. Below that it
     fails AA against the field. */
  --placeholder-alpha: 0.76;

  /* ─ type ───────────────────────────────────────────────── */

  --font-display: 'Figtree', system-ui, -apple-system, sans-serif;
  --font-body:    'Figtree', system-ui, -apple-system, sans-serif;
  --font-utility: 'Figtree', system-ui, -apple-system, sans-serif;

  /* The mark FX/THRESHOLD shows while it holds. Live text set in
     --font-display, not an image, so it follows the client's
     monogram and needs nothing regenerated when that changes.
     The quotes are part of the value: content: var(--mark). */
  --mark:      "MS";
  --step-mark: clamp(40px, 6vw, 72px);

  /* The progress bar runs the full width of the bottom edge, which
     is where a browser puts one and so needs no explaining. On the
     accent field its track and fill are the same white steps the
     rest of the site uses on that field, so nothing new is invented
     and it follows --accent for free. */
  --bar-height: 2px;

  /* List marker. The square the offence lists carry in front of each
     item, in --accent. Small enough to read as punctuation rather than
     as a bullet, which is what keeps the lists looking like a document
     and not like a slide. */
  --marker-size: 5px;

  --weight-light:   300;
  --weight-regular: 400;
  --weight-medium:  500;

  /* contract steps */
  --step--2: 12px;                          /* extension: eyebrow, label */
  --step--1: 14px;
  --step-0:  17px;
  --step-1:  18px;
  --step-2:  22px;
  --step-3:  clamp(36px, 4.4vw, 64px);
  --step-4:  clamp(56px, 8.4vw, 120px);

  /* extension: intermediate and role sizes this composition uses */
  --step-utility: 15px;
  --step-icon:    16px;
  --step-nav:     24px;
  --step-question: clamp(20px, 2vw, 26px);
  --step-row:      clamp(28px, 3vw, 40px);
  --step-contact:  clamp(28px, 3.2vw, 48px);

  /* extension: phone-band display sizes */
  --step-display-phone: clamp(40px, 12vw, 72px);
  --step-contact-phone: clamp(40px, 10vw, 72px);

  --lh-tight:   0.95;
  --lh-body:    1.5;

  /* extension: this composition uses seven more */
  --lh-heading: 1.05;
  --lh-title:   1.15;
  --lh-block:   1.2;
  --lh-list:    1.4;
  --lh-prose:   1.55;
  --lh-address: 1.65;
  --lh-stack:   1.7;

  --track-display: -0.01em;

  /* extension */
  --track-heading: -0.005em;
  --track-body:     0;
  --track-tight:    0.01em;
  --track-meta:     0.04em;
  --track-label:    0.08em;
  --track-eyebrow:  0.16em;

  /* ─ space ──────────────────────────────────────────────── */

  /* 0.85 tight · 1 default · 1.25 generous. Scales the ramp. */
  --density: 1;

  /* Value-named ramp. The number is the base pixel value at
     --density: 1. Every rung is used by this composition.
     md/README.md lists the ones used exactly once. */
  --sp-4:    calc(4px   * var(--density));
  --sp-6:    calc(6px   * var(--density));
  --sp-8:    calc(8px   * var(--density));
  --sp-9:    calc(9px   * var(--density));
  --sp-10:   calc(10px  * var(--density));
  --sp-12:   calc(12px  * var(--density));
  --sp-14:   calc(14px  * var(--density));
  --sp-16:   calc(16px  * var(--density));
  --sp-18:   calc(18px  * var(--density));
  --sp-20:   calc(20px  * var(--density));
  --sp-22:   calc(22px  * var(--density));
  --sp-24:   calc(24px  * var(--density));
  --sp-28:   calc(28px  * var(--density));
  --sp-32:   calc(32px  * var(--density));
  --sp-36:   calc(36px  * var(--density));
  --sp-40:   calc(40px  * var(--density));
  --sp-48:   calc(48px  * var(--density));
  --sp-56:   calc(56px  * var(--density));
  --sp-60:   calc(60px  * var(--density));
  --sp-64:   calc(64px  * var(--density));
  --sp-80:   calc(80px  * var(--density));
  --sp-96:   calc(96px  * var(--density));
  --sp-100:  calc(100px * var(--density));
  --sp-120:  calc(120px * var(--density));
  --sp-140:  calc(140px * var(--density));
  --sp-144:  calc(144px * var(--density));
  --sp-160:  calc(160px * var(--density));
  --sp-180:  calc(180px * var(--density));
  --sp-200:  calc(200px * var(--density));
  --sp-240:  calc(240px * var(--density));
  --sp-280:  calc(280px * var(--density));

  /* Contract aliases. A component written against the ht-kit
     eight-step ramp works here unchanged. */
  --space-1: var(--sp-4);
  --space-2: var(--sp-8);
  --space-3: var(--sp-12);
  --space-4: var(--sp-16);
  --space-5: var(--sp-24);
  --space-6: var(--sp-32);
  --space-7: var(--sp-48);
  --space-8: var(--sp-64);

  /* Two values per responsive pair, both defined once here.
     The bands in layout.css choose which one to consume, so no
     :root is ever redeclared inside a media query. */
  --gutter:          var(--sp-96);
  --gutter-wide:     var(--sp-64);
  --gutter-phone:    var(--sp-24);
  --section-y:       var(--sp-200);
  --section-y-phone: var(--sp-120);

  --max-width:        1440px;
  --max-width-narrow: 1240px;

  --measure:         480px;
  --measure-sm:      380px;
  --measure-lead:    600px;
  --measure-wide:    760px;
  --measure-brand:   280px;

  /* ─ form ───────────────────────────────────────────────── */

  --radius:        0;
  --radius-sm:     4px;
  --border:        1px;

  /* Clears the fixed header, with air. Used by the sticky
     headings on the services and contact pages. */
  --sticky-top:  120px;

  --tap-min:     44px;
  --offscreen:   -9999px;   /* honeypot parking */

  /* Composition insets. Viewport-relative, so they belong here
     rather than on the ramp. */
  --cap-offset:        6vw;

  /* Transform distances, not spacing. Never density-scaled:
     a nudge is a nudge at any density. */
  --nudge:           5px;
  --hamburger-shift: 7px;

  --shadow-nav:    0 2px 24px var(--accent-shadow);
  --shadow-drawer: 0 8px 24px var(--accent-shadow);

  /* Select chevron. A mask, so the colour comes from --accent
     rather than being baked into the data URI as the source
     did with %23022F77. */
  --chevron: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='7' viewBox='0 0 12 7'%3E%3Cpath d='M1 1l5 5 5-5' stroke='%23000' stroke-width='1.5' fill='none' stroke-linecap='square'/%3E%3C/svg%3E");
  --chevron-w: 12px;
  --chevron-h: 7px;

  /* ─ motion ─────────────────────────────────────────────── */

  /* Was cubic-bezier(.2, .6, .2, 1), which put 60% of the movement
     into the first 20% of the time. That is a sharp start, and on a
     large area it lands as a snap followed by a long drift rather than
     as one movement. This curve eases in as well as out, so a change
     begins gently, and it is what makes the difference between motion
     that is merely slow and motion that reads as smooth. */
  --ease:      cubic-bezier(.4, 0, .2, 1);

  /* Slowed across the board so the site reads as unhurried rather
     than snappy. --dur-fast governs hover feedback and is the one to
     keep short: past about 350ms a button stops feeling connected to
     the cursor. */
  --dur-fast:  240ms;
  --dur-base:  400ms;
  --dur-slow:  560ms;
  --dur-link:  280ms;   /* extension: nav and footer link colour */

  /* Extension. FX/WIPE on the home page practice rows: the accent
     sweeps in from the left rather than fading up everywhere at once.

     The sweep uses its own curve. --ease is an ease-in-out, which is
     right for something changing in place but wrong for something
     travelling: it makes the leading edge crawl away from the left
     margin. This one leaves at speed and settles at the right, so the
     row reads as being filled rather than as growing. */
  --dur-sweep:  400ms;
  --ease-sweep: cubic-bezier(.2, .5, .2, 1);

  /* The text inverts on its own, much faster clock. Each column waits
     for the sweep's leading edge to reach it, so nothing is ever white
     on white, and then flips quickly rather than cross-fading through
     grey.

     The delays are measured, not guessed. The three columns begin at
     1.8%, 14.1% and 57.9% of the row's width, and at --dur-sweep the
     leading edge reaches those points at 0ms, 17ms and 84ms. Retime
     the sweep and these have to be measured again. */
  --dur-invert:     50ms;
  --delay-invert-1:  0ms;   /* number, the edge covers it immediately */
  --delay-invert-2: 25ms;   /* title, edge crosses it 17ms to 67ms */
  --delay-invert-3: 110ms;  /* blurb, edge crosses it 84ms to 167ms */

  /* FX/RISE. Every stagger in this composition is a whole
     multiple of --stagger, so effects.css carries multipliers
     rather than durations. */
  --rise-y:  20px;
  --stagger: 26ms;

  /* FX/THRESHOLD, the first-load preloader. --dur-preload-in is
     the mark's entrance and runs inside the hold, so the whole
     effect is hold plus out, 940ms.

     --dur-preload-hold and --dur-preload-out are the same two
     numbers as HOLD and OUT at the top of js/modules/preloader.js.
     They are the one place in this template where a CSS value and a
     JS value have to agree. Change them together. */
  --ease-preload:      cubic-bezier(.16, 1, .3, 1);

  /* The bar's own curve, and it has to be its own. The site's --ease
     is front-loaded, which suits a panel arriving but is wrong for
     progress: it put the bar at 44% after 70ms and 91% by 250ms, so
     it read as already finished and then stuck. This one tracks close
     to linear early, 14% at 70ms and 50% at 250ms, then eases into
     completion so it does not stop dead. */
  --ease-bar:          cubic-bezier(.3, .2, .5, 1);
  --dur-preload-in:    300ms;   /* mark rises and fades in */
  --dur-preload-hold:  500ms;   /* panel is up for this long in total */
  --dur-preload-out:   440ms;   /* panel lifts away */

  /* FX/FACET, the home hero's field. Symmetric, and it has to
     be. --ease above is front-loaded, which is right for
     something arriving and wrong for something breathing: it
     would snap to each end of the drift and hang there, which
     reads as a stutter rather than a float. This one eases
     equally out of and into both turns, so a pane is never
     quite still and never quite fast.

     The eight drift periods live in effects.css rather than
     here. They are seconds-scale, this contract stops at
     --dur-slow, and they are per pane rather than a shared
     value, so a token each would be eight names carrying one
     idea. Same reasoning as the 3s rise safety reveal. */
  --ease-drift: cubic-bezier(.45, 0, .55, 1);

  /* No page transition on this site. --ease-page and the three
     --dur-page-* tokens are deliberately absent, and now cannot
     be added: FX/FACET holds the Signature slot and kit rule 8
     forbids a transition alongside another Signature effect.
     FX/THRESHOLD is unaffected, being Considered rather than
     Signature, and runs once per session rather than on every
     navigation. */
}

/* The @supports block that derived --accent-hover from --accent
   lived here. Removed, not disabled: --accent-hover is a literal
   second hue now, and a relative-colour rule would have overridden
   it wherever the syntax is supported. */
