/* tokens/fonts.css */
/* Self-hosted. Newsreader and Hanken Grotesk are both SIL Open Font License 1.1, so
   redistribution is permitted. Licences are in assets/fonts/.

   Latin and latin-ext only; Cyrillic and Vietnamese are not needed for a UK business site
   and would roughly double the payload.

   Hanken Grotesk is variable across 400 to 700, which is what the interface uses.

   Newsreader is a single static weight, 500, because that is the only weight the display
   face is ever set in. It shipped as a variable font carrying an optical-size axis nothing
   used, at 129KB for latin alone: larger than the full variable Google serves, and five
   times the 23KB a pinned 500 costs. Adding a display weight means adding a file, and that
   is the right trade for a face used on headings only.

   Newsreader italic is gone entirely. A heading is never italic here, and the two files
   were 236KB sitting in the repo waiting to be requested by accident. Hanken italic stays:
   emphasis inside body prose is legitimate, and it is only fetched if a page uses it.

   font-display: swap so text renders immediately in the fallback rather than blocking. */

@font-face {
  font-family: 'Hanken Grotesk';
  font-style: italic;
  font-weight: 400 700;
  font-display: swap;
  src: url('/ds/assets/fonts/hanken-grotesk-italic-latin-ext.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: 'Hanken Grotesk';
  font-style: italic;
  font-weight: 400 700;
  font-display: swap;
  src: url('/ds/assets/fonts/hanken-grotesk-italic-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'Hanken Grotesk';
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url('/ds/assets/fonts/hanken-grotesk-normal-latin-ext.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: 'Hanken Grotesk';
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url('/ds/assets/fonts/hanken-grotesk-normal-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'Newsreader';
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url('/ds/assets/fonts/newsreader-500-latin-ext.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: 'Newsreader';
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url('/ds/assets/fonts/newsreader-500-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

/* tokens/colors.css */
:root{
/* The mark's palette. Panel colours are given; overlap colours are consequences, generated where panels meet. */
--violet:#999BFF; /* panel 1 */
--cyan:#0DB4FF; /* panel 2 */
--green:#00CC99; /* panel 3 */
--overlap-blue:#0070F7; /* violet x cyan, generated. Primary accent. */
--overlap-teal:#008A99; /* cyan x green, generated. Secondary accent. */
--navy:#19255A; /* wordmark navy */
/* Neutrals carried from the existing build */
--rich-black:#0D1B2A;
--oxford:#1B263B;
--grey:#646468;
--offwhite:#FAFAFA;
--white:#FFFFFF;
/* Translucent panel tints (the mark is translucent; tints echo it) */
--tint-violet:rgba(153,155,255,.14);
--tint-cyan:rgba(13,180,255,.12);
--tint-green:rgba(0,204,153,.12);
--tint-navy:rgba(25,37,90,.06);
--tint-overlap-blue:rgba(0,112,247,.10);
--tint-overlap-teal:rgba(0,138,153,.10);
/* Audience. Content is written for one of three readers, and each reader keeps the same
   colour wherever they appear: an article tagged for owners, a step on the owner's
   proposition page, and a chip in a margin are all cyan. The mapping from a content tag to
   these tokens lives in app/src/lib/audience.ts. */
--audience-owner:var(--cyan);
--audience-owner-tint:var(--tint-cyan);
--audience-investor:var(--overlap-teal);
--audience-investor-tint:var(--tint-overlap-teal);
--audience-both:var(--navy);
--audience-both-tint:var(--tint-navy);

/* Failure. The mark has no red in it, and nothing generated between its panels reads as a
   refusal, so this is the one colour in the system that is chosen rather than derived. It
   exists because a form has to be able to say no, and saying it in an accent that also
   means "this is for owners" would be worse than adding a colour. Used for invalid fields
   and nothing else. */
--alert:#C4373B;
--alert-tint:rgba(196,55,59,.07);

/* Semantic */
--text-primary:var(--navy);
--text-secondary:#3E4770;
--text-muted:var(--grey);
--text-on-dark:var(--offwhite);
--text-on-dark-muted:rgba(250,250,250,.64);
--surface-page:var(--white);
--surface-tint:var(--offwhite);
--surface-raised:var(--white);
--surface-dark:var(--navy);
--surface-deep:var(--rich-black);
--accent:var(--overlap-blue);
--accent-2:var(--overlap-teal);
--link:var(--overlap-blue);
/* A placeholder is an example, not an answer. At text-muted it reads as a filled field,
   which is worse than no placeholder at all: the reader thinks the form is half done. */
--placeholder:rgba(25,37,90,.34);
--border-subtle:rgba(25,37,90,.14);
--border-strong:rgba(25,37,90,.32);
--border-on-dark:rgba(250,250,250,.18);
--focus-ring:0 0 0 3px rgba(0,112,247,.28);
}

/* tokens/typography.css */
:root{
--font-display:'Newsreader',Georgia,'Times New Roman',serif; /* headings, wordmark-adjacent, pull quotes */
--font-text:'Hanken Grotesk',-apple-system,'Segoe UI',sans-serif; /* body, UI, labels */
/* Scale */
--text-xs:.8125rem; /* 13 eyebrows, legal */
--text-sm:.875rem; /* 14 UI, captions */
--text-base:1rem; /* 16 */
--text-md:1.125rem; /* 18 body on marketing pages */
--text-lg:1.375rem; /* 22 lead paragraphs */
--text-xl:clamp(1.375rem,1.1rem + 1.2vw,1.75rem); /* 22 to 28, h3 */
--text-2xl:clamp(1.625rem,1.2rem + 2vw,2.25rem); /* 26 to 36, h2 */
--text-3xl:clamp(2rem,1.4rem + 3vw,3rem); /* 32 to 48, h1 */
--text-4xl:clamp(2.25rem,1.3rem + 4.6vw,4rem); /* 36 to 64, display */
--text-5xl:clamp(2.5rem,1.2rem + 6.4vw,5.25rem); /* 40 to 84, hero */
/* Leading */
--leading-display:1.04;
--leading-heading:1.12;
--leading-body:1.55;
--leading-tight:1.3;
/* Tracking */
--tracking-display:-0.015em;
--tracking-eyebrow:.14em;
/* Weights: serif 400/500/600, sans 400/500/600/700 */
--weight-display:500;
}
body{font-family:var(--font-text);color:var(--text-primary);font-size:var(--text-base);line-height:var(--leading-body);-webkit-font-smoothing:antialiased}
a{color:var(--link);text-decoration:none}
a:hover{color:var(--navy);text-decoration:underline;text-underline-offset:3px}
/* Chrome and cells are targets in their own right: the whole cell highlights, so an
   underline on the text inside would be a second, competing affordance. */
header a:hover,header a,.lattice-table a:hover,.no-underline:hover{text-decoration:none}

/* tokens/spacing.css */
:root{
--space-1:4px;--space-2:8px;--space-3:12px;--space-4:16px;--space-5:24px;--space-6:32px;--space-7:48px;--space-8:64px;--space-9:96px;--space-10:128px;
--measure:66ch; /* long-form text width */
--container:1120px; /* page content width */
--gutter:24px;
}

/* tokens/layout.css */
/* Responsive layout tokens.
   The components are inline-styled, and inline styles cannot carry media queries. So the
   components reference these variables and the breakpoints redefine them. One place to
   change the layout, no component rewrites.
   Mobile first: the base values are the narrow ones. */
:root{
--grid-hero:1fr;              /* hero: text over mark */
--grid-cards:1fr;             /* entity cells */
--grid-entities:1fr;          /* the family lattice, including the open cell */
--grid-split:1fr;             /* two-up panels */
--section-y:48px;             /* vertical section rhythm */
--section-y-lg:56px;
--hero-gap:32px;
--stack-gap:24px;
--mark-width:56%;             /* hero mark */
--flow-dir:column;            /* rows that must stack on small screens */
--flow-align:flex-start;
--flow-end:flex-start;        /* pushed to the container's far edge, once there is one */
--nav-display:none;           /* desktop nav hidden until there is room */
--menu-display:inline-flex;   /* mobile menu button */
--cta-display:none;           /* header CTA needs room */
}

/* minmax(0,1fr), never a bare 1fr.
   1fr is minmax(auto,1fr), and auto is the item's automatic minimum size. A cell carrying
   .cell-sq3 has an aspect ratio, so its minimum width is derived from the row's height and
   can be wider than its share of the row. The track then refuses to shrink to it and the
   whole table hangs past the container's right edge. A zero floor makes the columns
   exactly equal, which is what an empty slot in a four-up depends on. */
@media (min-width:600px){
  :root{
    --grid-cards:repeat(2,minmax(0,1fr));
    --grid-entities:repeat(2,minmax(0,1fr));
    --section-y:56px;
    --mark-width:44%;
  }
}

@media (min-width:900px){
  :root{
    --grid-hero:1.5fr 1fr;
    --grid-cards:repeat(3,minmax(0,1fr));
    --grid-entities:repeat(4,minmax(0,1fr));
    --grid-split:1.4fr 1fr;
    --section-y:72px;
    --section-y-lg:88px;
    --hero-gap:64px;
    --stack-gap:32px;
    --mark-width:82%;
    --flow-dir:row;
    --flow-align:center;
    --flow-end:flex-end;
    --nav-display:flex;
    --menu-display:none;
    --cta-display:grid;   /* grid, so the CTA cell can hatch the space beside itself */
  }
}

/* Nothing should ever push the page sideways. */
/* clip, not hidden: overflow-x:hidden makes this a scroll container, which silently
   breaks position:sticky on the header. clip guards the same way without that. */
html,body{max-width:100%;overflow-x:clip}
*,*::before,*::after{box-sizing:border-box}
img,svg{max-width:100%;height:auto}

/* The header in three parts.

     1fr   |   the container   |   1fr
    logo   |       nav         |   CTA

   The logo sits against the page edge, the nav occupies exactly the content container, and
   the CTA sits against the other edge. Because the nav and the mega menu are both equal
   fractions of the same container width, their verticals align by arithmetic rather than
   by luck. No auto columns, so nothing can resolve differently between the two rows. */
:root{
  /* Logo, then the toggle hard against the other edge. One row, two cells: with a single
     column the toggle has nowhere to sit but underneath, which is what it was doing. */
  --header-cols:1fr auto;
  --header-max:none;
  --nav-inner:none;
  --nav-grid:none;    /* the nav must be a grid, not a flex row, or its columns are ignored */
  --nav-pad:20px;
}
@media (min-width:900px){
  :root{
    /* auto, not 1fr, on the ends; and a middle that may shrink.
       `1fr min(container,100%) 1fr` pinned the nav to the full container and let the ends
       take whatever was left, so below about 1540 there was not enough for both and the
       CTA was pushed off the right edge. The ends are now sized by their content and the
       nav gives way first, which is the right order: an internal link losing a few pixels
       costs nothing, a call to action disappearing costs the enquiry.

       Above the point where everything fits, the ends absorb the surplus and their own
       hatched cells take it, so the logo and the CTA hold their size at any width. */
    --header-cols:auto minmax(0,var(--container)) auto;
    --nav-inner:repeat(4,minmax(0,1fr));
    --nav-grid:grid;
    --nav-pad:24px;
  }
}

/* Long-form: a reading column and a contents rail. The rail only exists where there is
   room for it, so below 1000px the article is a single column. */
:root{
  --article-cols:1fr;
  --toc-display:none;
  --share-inline-display:block;   /* no rail to put it in */
}
@media (min-width:1000px){
  :root{
    --article-cols:minmax(0,1fr) 260px;
    --toc-display:block;
    --share-inline-display:none;
  }
}

/* tokens/lattice.css */
/* THE LATTICE
   Derived from the mark, not designed alongside it.

   Measured from compound-mark.svg: every diagonal edge sits at 29.9 to 30.0 degrees and
   every other edge is vertical. The violet panel's horizontal span divided by its vertical
   edge is 1.731, against sqrt 3 = 1.732. The mark is an isometric drawing.

   The rule that falls out of that, and which everything here obeys:

     Pattern is isometric.  Layout is orthogonal at sqrt 3.  The 30 degree cut is the
     only place the two touch.

   Patterns are SVG rather than CSS gradients so the angle is genuinely 30.0 degrees
   rather than an approximation that drifts at large sizes.

   The module is 140, not a round 120, because 1120 / 140 = 8 exactly and each of the four
   nav columns is 280, or two modules. A module that does not divide the container can
   never line up with it, however carefully anything is nudged.

   Fields are anchored to the container rather than the viewport, so a vertical always
   falls on the container's left edge whatever the window is doing. */

:root{
  /* Geometry */
  --iso-w:140px;              /* horizontal module: 1120 container / 140 = 8 exactly */
  --iso-h:80.829px;           /* = 140 x tan(30). the rise across one module */
  --iso-ratio:1.7321;         /* sqrt 3 */

  /* Layout module, the mark's proportion without the mark's shear */
  --cell-w:180px;
  --cell-h:104px;             /* 180 / 1.7321 */

  /* The 30 degree cut, derived rather than hardcoded.
     59 x 34 is 29.954 degrees and 34 x 20 is 30.466: close, but wrong, and wrong in
     different directions. Deriving the drop from tan(30) makes it exact at any width. */
  --tan30:0.57735;
  --cut-x:56px;
  --cut-y:calc(var(--cut-x) * var(--tan30));      /* 32.33 */
  --cut-sm-x:32px;
  --cut-sm-y:calc(var(--cut-sm-x) * var(--tan30)); /* 18.48 */
  /* The smallest tier, for cells of 50px or less. At that size the sm cut takes most of
     the corner off and fights the three square edges it is attached to: the shape stops
     reading as a square with a nick and starts reading as a badly drawn pentagon. */
  --cut-xs-x:10px;
  --cut-xs-y:calc(var(--cut-xs-x) * var(--tan30));  /* 5.77 */

  /* Rules */
  --rule:rgba(25,37,90,.11);
  --rule-strong:rgba(25,37,90,.18);
  --rule-dark:rgba(250,250,250,.14);
  --rule-dark-strong:rgba(250,250,250,.22);
}


.lattice{
  background-image:url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' width='140' height='80.829' viewBox='0 0 140 80.829'><path d='M0%2C80.829 L140%2C0' stroke='%2319255A' stroke-opacity='.13' stroke-width='1' fill='none'/><path d='M0%2C0 L0%2C80.829' stroke='%2319255A' stroke-opacity='.13' stroke-width='1' fill='none'/></svg>");
  background-size:var(--iso-w) var(--iso-h);
  background-position:calc(50% - (var(--container) / 2)) 0;
}

.lattice-nodes{
  background-image:url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' width='140' height='80.829' viewBox='0 0 140 80.829'><path d='M0%2C80.829 L140%2C0' stroke='%2319255A' stroke-opacity='.09' stroke-width='1' fill='none'/><path d='M0%2C0 L0%2C80.829' stroke='%2319255A' stroke-opacity='.09' stroke-width='1' fill='none'/><path d='M-5%2C80.829 l10%2C0 l5%2C-2.9 l-10%2C0 z' fill='%2319255A' fill-opacity='.30'/><path d='M135%2C0 l10%2C0 l5%2C-2.9 l-10%2C0 z' fill='%2319255A' fill-opacity='.30'/></svg>");
  background-size:var(--iso-w) var(--iso-h);
  background-position:calc(50% - (var(--container) / 2)) 0;
}

.lattice-iso{
  background-image:url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' width='140' height='80.829' viewBox='0 0 140 80.829'><path d='M0%2C80.829 L140%2C0' stroke='%2319255A' stroke-opacity='.10' stroke-width='1' fill='none'/><path d='M0%2C0 L140%2C80.829' stroke='%2319255A' stroke-opacity='.10' stroke-width='1' fill='none'/><path d='M0%2C0 L0%2C80.829' stroke='%2319255A' stroke-opacity='.10' stroke-width='1' fill='none'/></svg>");
  background-size:var(--iso-w) var(--iso-h);
  background-position:calc(50% - (var(--container) / 2)) 0;
}

.lattice-sparse{
  background-image:url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' width='140' height='80.829' viewBox='0 0 140 80.829'><path d='M0%2C80.829 L140%2C0' stroke='%2319255A' stroke-opacity='.08' stroke-width='1' fill='none'/></svg>");
  background-size:var(--iso-w) var(--iso-h);
  background-position:calc(50% - (var(--container) / 2)) 0;
}

.lattice-dark{
  background-image:url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' width='140' height='80.829' viewBox='0 0 140 80.829'><path d='M0%2C80.829 L140%2C0' stroke='%23FAFAFA' stroke-opacity='.13' stroke-width='1' fill='none'/><path d='M0%2C0 L0%2C80.829' stroke='%23FAFAFA' stroke-opacity='.13' stroke-width='1' fill='none'/></svg>");
  background-size:var(--iso-w) var(--iso-h);
  background-position:calc(50% - (var(--container) / 2)) 0;
}

.lattice-dark-sparse{
  background-image:url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' width='140' height='80.829' viewBox='0 0 140 80.829'><path d='M0%2C80.829 L140%2C0' stroke='%23FAFAFA' stroke-opacity='.09' stroke-width='1' fill='none'/></svg>");
  background-size:var(--iso-w) var(--iso-h);
  background-position:calc(50% - (var(--container) / 2)) 0;
}

.lattice-dark-nodes{
  background-image:url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' width='140' height='80.829' viewBox='0 0 140 80.829'><path d='M0%2C80.829 L140%2C0' stroke='%23FAFAFA' stroke-opacity='.10' stroke-width='1' fill='none'/><path d='M0%2C0 L0%2C80.829' stroke='%23FAFAFA' stroke-opacity='.10' stroke-width='1' fill='none'/><path d='M-5%2C80.829 l10%2C0 l5%2C-2.9 l-10%2C0 z' fill='%23FAFAFA' fill-opacity='.28'/><path d='M135%2C0 l10%2C0 l5%2C-2.9 l-10%2C0 z' fill='%23FAFAFA' fill-opacity='.28'/></svg>");
  background-size:var(--iso-w) var(--iso-h);
  background-position:calc(50% - (var(--container) / 2)) 0;
}


/* The cut. Applied to a cell, it removes the bottom right corner at 30 degrees. */
.cut{clip-path:polygon(0 0,100% 0,100% calc(100% - var(--cut-y)),calc(100% - var(--cut-x)) 100%,0 100%)}
.cut-sm{clip-path:polygon(0 0,100% 0,100% calc(100% - var(--cut-sm-y)),calc(100% - var(--cut-sm-x)) 100%,0 100%)}
.cut-xs{clip-path:polygon(0 0,100% 0,100% calc(100% - var(--cut-xs-y)),calc(100% - var(--cut-xs-x)) 100%,0 100%)}

/* The cell table. Borders collapse to single hairlines; empty cells stay empty. */
.lattice-table{display:grid;border-top:1px solid var(--rule-strong);border-left:1px solid var(--rule-strong)}
.lattice-table > *{border-right:1px solid var(--rule-strong);border-bottom:1px solid var(--rule-strong)}
.lattice-table.on-dark{border-top-color:var(--rule-dark);border-left-color:var(--rule-dark)}
.lattice-table.on-dark > *{border-right-color:var(--rule-dark);border-bottom-color:var(--rule-dark)}

/* A node, for use outside a pattern: a 30 degree parallelogram. */
.node{display:inline-block;width:14px;height:9px;
  clip-path:polygon(17% 0,100% 0,83% 100%,0 100%)}

@media (prefers-reduced-motion:no-preference){
  .lattice-fade{animation:lattice-in var(--duration) var(--ease) both}
}
@keyframes lattice-in{from{opacity:0}to{opacity:1}}



/* ------------------------------------------------------------
   WHERE 90 MEETS 30

   A rectangle of ratio sqrt 3 : 1 has a corner-to-corner diagonal of
   atan(1 / sqrt 3) = 30.00 degrees exactly. So the cell's own diagonal IS the lattice
   line. The orthogonal table and the isometric pattern are the same geometry, provided
   the cell holds the proportion.

   .cell-mark draws one 30 degree stroke anchored to the cell's bottom left corner. The
   angle is exact at any cell size because the tile is never stretched: only where the cell
   is sqrt 3 : 1 does the stroke land precisely on the opposite corner, and that is the
   resolved case worth aiming for.

   Note on .cut: clip-path removes the element's border along with the corner, so a cut
   cell inside .lattice-table loses its own edge. Use .cut only on cells that draw no
   border of their own.
   ------------------------------------------------------------ */
.cell-mark{
  background-image:url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' width='120' height='69.28' viewBox='0 0 120 69.28'><path d='M0%2C69.28 L120%2C0' stroke='%2319255A' stroke-opacity='.11' stroke-width='1' fill='none'/></svg>");
  background-repeat:no-repeat;
  background-position:left bottom;
  background-size:var(--iso-w) var(--iso-h);
  background-position:calc(50% - (var(--container) / 2)) 0;
}
.cell-mark.on-dark{background-image:url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' width='120' height='69.28' viewBox='0 0 120 69.28'><path d='M0%2C69.28 L120%2C0' stroke='%23FAFAFA' stroke-opacity='.11' stroke-width='1' fill='none'/></svg>")}

/* The resolved cell: sqrt 3 : 1, so .cell-mark lands corner to corner. */
.cell-sq3{aspect-ratio:var(--iso-ratio)}
/* Only inside a guaranteed sqrt 3 cell may the stroke stretch: the ratio keeps it at 30. */
.cell-sq3.cell-mark{background-size:100% 100%}

/* ------------------------------------------------------------
   THE CUT, WITH ITS BORDER INTACT

   clip-path removes the corner and the border with it, so the cut edge has to be drawn
   back. The pseudo-element is a 59 x 34 box whose own anti-diagonal is the cut: 59 and 34
   give atan(34/59) = 29.95 degrees, so the angle comes from the box rather than from a
   number anyone has to maintain.

   The line is drawn at double width because the clip path bisects it: half falls outside
   the shape, leaving a clean 1px sitting exactly on the cut edge.

   --cut-line is the hook for interaction: set it to an accent and the wedge inks in.
   ------------------------------------------------------------ */
.cut{position:relative}
.cut::after{
  content:'';
  position:absolute;
  right:0;bottom:0;
  width:var(--cut-x);height:var(--cut-y);
  /* to bottom right, not to top right. CSS corner keywords do not point along the box
     diagonal: for "to top right" the spec puts the perpendicular through the top-left and
     bottom-right corners, so the constant-colour line runs TL to BR. The cut runs BL to
     TR, which is the other diagonal. "to bottom right" gives the one we want. */
  background:linear-gradient(to bottom right,
    transparent calc(50% - 1px),
    var(--cut-line,var(--rule-strong)) calc(50% - 1px),
    var(--cut-line,var(--rule-strong)) calc(50% + 1px),
    transparent calc(50% + 1px));
  transition:background var(--duration-fast) var(--ease);
  pointer-events:none;
}
.cut-sm::after{width:var(--cut-sm-x);height:var(--cut-sm-y)}
.cut-xs::after{width:var(--cut-xs-x);height:var(--cut-xs-y)}

/* ------------------------------------------------------------
   WHERE THE SLANT IS ALLOWED

   The pattern is structural, not decorative. Repeated in every cell it stops meaning
   anything and starts looking like a texture someone left switched on. It is permitted in
   three places only:

     1. A hero or feature ground, once per page.
     2. An empty cell, where the absence is the point.
     3. A wedge on a cell corner, which is the cut rather than the field.

   Everywhere else, colour does the work: panel tints at 10 to 14 percent wash a feature
   area, and a tint tells you what something is rather than ornamenting it.
   ------------------------------------------------------------ */

/* Accent tints, keyed to the same names the CMS uses for an entity's accent. */
.wash-violet{background:var(--tint-violet)}
.wash-cyan{background:var(--tint-cyan)}
.wash-green{background:var(--tint-green)}
.wash-overlap-blue{background:var(--tint-overlap-blue)}
.wash-overlap-teal{background:var(--tint-overlap-teal)}
.wash-navy{background:var(--tint-navy)}

/* ------------------------------------------------------------
   INTERACTION

   Nothing lifts. Things ink in.

   Shadows imply objects floating above a surface. The lattice is a drawn plane, so
   elevation contradicts it. Hover is expressed with the system's own vocabulary instead:
   the wedge takes the accent, the ground tints, the arrow moves 4px.

   Motion budget: opacity, colour, and translation up to 4px. No scale, because scale
   implies depth. No bounce, because nothing here is springy.
   ------------------------------------------------------------ */
:root{
  --move:4px;                 /* the only translation distance in the system */
  --focus-ring:0 0 0 3px rgba(0,112,247,.28);
}

.ink{transition:background var(--duration-fast) var(--ease),color var(--duration-fast) var(--ease),border-color var(--duration-fast) var(--ease)}

/* An arrow that advances on hover. The parent carries .advance. */
.advance .arrow{display:inline-block;transition:transform var(--duration-fast) var(--ease)}
.advance:hover .arrow{transform:translateX(var(--move))}

/* Square focus, because the system is square. Never removed, only restyled. */
a:focus-visible,button:focus-visible,input:focus-visible,select:focus-visible,textarea:focus-visible{
  outline:none;box-shadow:var(--focus-ring);border-radius:0;
}

@media (prefers-reduced-motion:reduce){
  *,*::before,*::after{transition-duration:.01ms !important;animation-duration:.01ms !important}
  .advance:hover .arrow{transform:none}
}


/* ------------------------------------------------------------
   THE EMPTY CELL

   An empty cell is content: the family is not finished, and the blank cell is the
   argument. The field patterns are drawn at the 140px module, which inside a single cell
   gives one or two lines and reads as a mistake rather than a texture. At cell scale the
   slant has to be condensed to register at all.

   The angle is still 30 degrees. A repeating gradient's stripes run perpendicular to its
   axis, so an axis at -30deg puts the stripes 30 degrees above the horizontal, which is
   the mark's own diagonal.

   Sets background-image only, so a cell can carry its own background colour underneath.
   Set that colour with background-color, never the background shorthand, which would
   reset the image.
   ------------------------------------------------------------ */
.hatch{
  background-image:repeating-linear-gradient(-30deg,
    transparent,transparent 7px,
    rgba(25,37,90,.045) 7px,rgba(25,37,90,.045) 8px);
}
.hatch.on-dark{
  background-image:repeating-linear-gradient(-30deg,
    transparent,transparent 7px,
    rgba(250,250,250,.05) 7px,rgba(250,250,250,.05) 8px);
}


/* A mega menu link is a cell too, and inks the same way. */
.mega-link{transition:background var(--duration-fast) var(--ease),color var(--duration-fast) var(--ease)}
.mega-link:hover,.mega-link:focus-visible{background:var(--surface-tint)}


/* ------------------------------------------------------------
   THE SHARE GROUP

   Three cells of one object, divided by verticals, the way the split button is built. Three
   separate bordered squares with gaps between them would be three objects, and the system
   does not have floating objects in it.

   Hover inks the cell in overlap blue, the same generated colour the button's arrow cell
   takes, so every "this one is live" state on the site is the same colour.
   ------------------------------------------------------------ */
.share-row{display:flex;gap:12px}
.share{display:inline-flex;border:1px solid var(--rule-strong);background:var(--white)}
.share-cell{position:relative;display:inline-flex;align-items:center;justify-content:center;
  width:44px;height:42px;color:var(--navy);text-decoration:none;background:transparent;
  font-family:var(--font-text);font-size:13px;font-weight:600;line-height:1;
  border:0;border-left:1px solid var(--rule-strong);cursor:pointer;
  transition:background var(--duration-fast) var(--ease),color var(--duration-fast) var(--ease)}
.share-cell:first-child{border-left:0}

/* The cut belongs to the group, not to each cell, and it is a real cut: the corner is
   clipped away and the hairline redrawn on the new edge. A diagonal drawn inside a corner
   that stays square is two shapes arguing, which is what a wedge per cell looked like.
   One object, one cut, at the smallest tier the system has. */

/* The glyph advances 4px, the same distance every other moving thing here travels. */
.share-glyph{display:block;transition:transform var(--duration-fast) var(--ease)}
.share-cell:hover .share-glyph,.share-cell:focus-visible .share-glyph{transform:translateY(-4px)}
.share-cell:hover,.share-cell:focus-visible{background:var(--share-tint,var(--tint-navy));
  color:var(--share-accent,var(--accent))}

/* One caption for the whole group, which reads out whatever is under the pointer.
   It sits on its own line above the cells and reserves two lines of height whatever it
   currently says. The label changes width as it changes word: "on LinkedIn" is three times
   the width of "on X", and a caption sharing a line with the cells drags them sideways
   every time the pointer moves. Reserved height, fixed position, nothing jumps.

   The word that changes is the only part that takes the accent. "Share" is constant, so it
   stays quiet and the eye reads the change rather than the whole line. */
.share-row{flex-direction:column;align-items:flex-start;gap:10px}
.share-caption{display:block;min-height:2.8em;line-height:1.4;
  font-size:var(--text-xs);font-weight:600;letter-spacing:var(--tracking-eyebrow);
  text-transform:uppercase;color:var(--grey)}
.share-target{color:var(--accent);font-weight:700;
  transition:color var(--duration-fast) var(--ease)}

/* On the dark article header the same group, rules and all, inverted. */
.share.on-dark{border-color:var(--rule-dark-strong);background:transparent;
  --cut-line:var(--rule-dark-strong)}
.share.on-dark .share-cell{color:var(--offwhite);border-left-color:var(--rule-dark-strong)}
.share.on-dark .share-cell:first-child{border-left:0}
.share.on-dark .share-cell:hover,.share.on-dark .share-cell:focus-visible{
  background:rgba(250,250,250,.08);color:var(--share-accent,var(--cyan))}


/* ------------------------------------------------------------
   THE CONTENTS RAIL

   One plate rather than a list floating beside the text: the sections are cells, and the
   last cell is the way out. It travels with the reader, so the question the article is
   answering never scrolls away from the answer to it.
   ------------------------------------------------------------ */
/* Not sticky here. position:sticky moves an element within its containing block, and this
   one's parent is a grid item sized to its own content, which leaves nowhere to move. The
   page makes the grid item itself sticky instead, where the containing block is the whole
   grid area. */
.rail{border:1px solid var(--rule-strong);background:var(--white)}
.rail-head{padding:var(--space-4) var(--space-5);border-bottom:1px solid var(--rule-strong);
  font-size:var(--text-xs);font-weight:600;letter-spacing:var(--tracking-eyebrow);
  text-transform:uppercase;color:var(--grey)}
.rail-cta{display:flex;align-items:center;justify-content:space-between;gap:12px;
  padding:var(--space-4) var(--space-5);border-top:1px solid var(--rule-strong);
  background:var(--navy);color:var(--offwhite);text-decoration:none;
  font-size:var(--text-sm);font-weight:600;
  transition:background var(--duration-fast) var(--ease)}
.rail-cta:hover{background:var(--rich-black)}
.rail-cta .arrow{transition:transform var(--duration-fast) var(--ease)}
.rail-cta:hover .arrow{transform:translateX(var(--move))}
.rail-share{padding:var(--space-4) var(--space-5);border-top:1px solid var(--rule-strong);
  background:var(--surface-tint)}
.rail-share .share-row{gap:8px}


/* ------------------------------------------------------------
   THE FORM PLATE

   A form is a ledger too. Fields are cells in one ruled table rather than boxes stacked
   down a column: the cell's own rules are the field's edges, so there is no second border
   drawn inside a border, and the plate reads as a single object the way the footer does.

   Focus inks the cell rather than outlining the input, which is the same move the rest of
   the system makes: nothing lifts, the ground takes the colour.
   ------------------------------------------------------------ */
.formplate{display:grid;grid-template-columns:1fr;border:1px solid var(--rule-strong);background:var(--white)}
@media (min-width:900px){.formplate{grid-template-columns:repeat(2,minmax(0,1fr))}}

.formcell{padding:var(--space-5);border-bottom:1px solid var(--rule);transition:background var(--duration-fast) var(--ease)}
.formcell:focus-within{background:var(--tint-navy)}
@media (min-width:900px){
  .formplate > .formcell{border-right:1px solid var(--rule)}
  .formplate > .formcell:nth-child(2n),
  .formplate > .formcell-wide{border-right:0}
}
.formcell-wide{grid-column:1 / -1}
.formplate > .formcell:last-child{border-bottom:0}

.formlabel{display:block;font-size:11px;font-weight:600;letter-spacing:.12em;
  text-transform:uppercase;color:var(--grey);margin-bottom:10px}

/* The input draws nothing. The cell around it is the input's edge. */
.formfield{display:block;width:100%;border:0;background:transparent;padding:0;margin:0;
  font-family:var(--font-text);font-size:var(--text-md);line-height:1.5;color:var(--navy);
  resize:vertical}
.formfield:focus{outline:none;box-shadow:none}
.formfield::placeholder{color:var(--placeholder);opacity:1}

/* VALIDATION
   :user-invalid, not :invalid. :invalid is true the moment the page loads, so a form built
   on it greets a reader by telling them everything they have not filled in yet. This waits
   until they have actually typed something or tried to submit.

   The cell fails, not the input: the ground tints, the rule on the left goes to the alert
   colour, and the hint that was always in the markup becomes visible. Nothing appears from
   nowhere and nothing shifts, because the hint reserves its line whether or not it shows. */
.formhint{display:block;margin-top:8px;font-size:var(--text-sm);line-height:1.4;
  color:var(--alert);visibility:hidden}
.formcell:has(:user-invalid){background:var(--alert-tint);box-shadow:inset 2px 0 0 var(--alert)}
.formcell:has(:user-invalid) .formlabel{color:var(--alert)}
.formcell:has(:user-invalid) .formhint{visibility:visible}

/* Filled and valid: the label takes the ink it earns, quietly. No ticks. */
.formcell:has(.formfield:user-valid) .formlabel{color:var(--navy)}

/* The reader picks themselves, and picks up their colour doing it. The accents are the
   audience tokens, so a choice made here matches the same reader's colour everywhere. */
.choice{display:grid;grid-template-columns:1fr;border-top:1px solid var(--rule)}
@media (min-width:900px){.choice{grid-template-columns:repeat(3,minmax(0,1fr))}}
.choice-cell{position:relative;display:flex;align-items:center;gap:10px;cursor:pointer;
  padding:var(--space-4) var(--space-5);border-bottom:1px solid var(--rule);
  font-size:var(--text-base);color:var(--text-secondary);
  transition:background var(--duration-fast) var(--ease),color var(--duration-fast) var(--ease)}
@media (min-width:900px){
  .choice-cell{border-bottom:0;border-right:1px solid var(--rule)}
  .choice-cell:last-child{border-right:0}
}
.choice-cell input{position:absolute;opacity:0;width:0;height:0}
.choice-node{width:14px;height:9px;flex:none;background:var(--rule-strong);
  clip-path:polygon(17% 0,100% 0,83% 100%,0 100%);
  transition:background var(--duration-fast) var(--ease)}
.choice-cell:hover{background:var(--surface-tint)}
.choice-cell:has(input:checked){background:var(--choice-tint);color:var(--navy);font-weight:600}
.choice-cell:has(input:checked) .choice-node{background:var(--choice-accent)}
.choice-cell:has(input:focus-visible){box-shadow:var(--focus-ring)}


/* ------------------------------------------------------------
   MARGIN ANNOTATION

   A row with a ruled rail down each side, carrying the marginalia of a prospectus:
   numbered items, dates, and figures that can be checked. The labels read bottom to top,
   so the rails stay narrow and the reading column keeps its measure.

   The ground inside is the 30 degree field, never a squared one. The rails are already
   the vertical event, and a second set of verticals inside them would compete with the
   two lines that give the row its shape. One direction, drawn once.

   Rows stack into a list: consecutive rows drop their top border so the rules collapse
   to single hairlines, as in .lattice-table.
   ------------------------------------------------------------ */
:root{--annot-rail:40px}
@media (min-width:900px){:root{--annot-rail:96px}}

.annot{
  display:grid;
  grid-template-columns:var(--annot-rail) minmax(0,1fr) var(--annot-rail);
  border:1px solid var(--rule-strong);
  background:var(--white);
  color:inherit;
  text-decoration:none;
}
.annot + .annot{border-top:0}

/* One rail. A collection row is annotated on both sides because both sides say something:
   what it is on the left, where it sits in the run on the right. A form has no run to sit
   in, so the right rail would be a margin with nothing to annotate. */
.annot-single{grid-template-columns:var(--annot-rail) minmax(0,1fr)}

.annot-rail{
  display:flex;
  flex-direction:column;
  justify-content:space-between;
  align-items:center;
  /* Tight, because a rail's own height must not set the row's. Marginalia are labels, not
     content: keep them to a word or two and the row is sized by what it says. */
  gap:var(--space-4);
  padding:var(--space-4) 0;
  border-right:1px solid var(--rule);
}
.annot-rail-end{border-right:0;border-left:1px solid var(--rule)}

.annot-mark{
  writing-mode:vertical-rl;
  transform:rotate(180deg);
  font-size:10.5px;
  font-weight:600;
  letter-spacing:.16em;
  text-transform:uppercase;
  color:var(--grey);
  white-space:nowrap;
}

.annot-body{padding:var(--space-6)}

/* Hover inks the ground and takes the marginalia up to full strength. Nothing lifts.
   Scoped to rows that are links: the same shell wraps the enquiry form, and a form that
   tints when the pointer crosses it reads as a control that is about to do something. */
a.annot:hover .annot-body{background-color:var(--tint-navy)}
a.annot:hover .annot-mark{color:var(--navy)}
a.annot:hover .annot-mark[data-accent]{color:var(--annot-accent,var(--accent))}


/* ------------------------------------------------------------
   THE LEDGER

   The footer as a plate rather than a band: a panel exactly the width of the container,
   ruled into cells. Every link is a cell, the columns run to different lengths, and the
   grid carries on regardless, so the empty cells are part of the reading.

   Light, not navy. A full-bleed dark band closing the page directly above a dark plate
   reads as one mass with a stripe of white through it, and the plate loses the edge that
   made it a plate. The closing argument keeps the navy and the width, because it is the
   loudest thing on the site; the ledger below it goes to white and hairlines, and the
   drawn field lives in the empty cells where the pattern has something to say.

   Laid out column by column (grid-auto-flow:column across five rows) rather than cell by
   cell in row order. The visual result is the same table, but the DOM order stays Brand,
   Compound, The family, Legal, which is the order it must collapse to on a phone and the
   order a screen reader should hear. Rows are auto height and shared by all four columns,
   so the horizontal rules line up by construction rather than by matching paddings.

   Every column must be five row-units tall, counting spans. A column that is short by one
   pushes the next column's first cell into the gap.
   ------------------------------------------------------------ */
.ledger{display:grid;grid-template-columns:1fr;background:var(--white);
  border:1px solid var(--rule-strong)}
.ledger > *{border-bottom:1px solid var(--rule)}
.ledger > *:last-child{border-bottom:0}

/* Stacked, the plate is one column: the spacer cells have nothing to space. */
.ledger-spacer{display:none}

/* A cell that is a link is a link across the whole cell, not just across its words. The
   ground inks, the type goes to full strength, and the pointer target is the rectangle the
   reader can already see. */
.ledger a{transition:background var(--duration-fast) var(--ease),color var(--duration-fast) var(--ease)}
.ledger a:hover,.ledger a:focus-visible{background:var(--surface-tint);color:var(--navy)}

@media (min-width:900px){
  .ledger{grid-template-columns:1.6fr 1fr 1fr 1fr;grid-template-rows:repeat(5,auto);grid-auto-flow:column}
  .ledger > *{border-right:1px solid var(--rule)}
  .ledger-spacer{display:block}
  /* The plate draws its own edge, so cells sitting on it draw none. */
  .ledger-end{border-right:0}
  .ledger-foot{border-bottom:0}
}

/* ------------------------------------------------------------
   THE OUTBOUND ARROW

   The arrow character sits at 45 degrees, and every other diagonal in this system is 30.
   A glyph cannot be corrected without rotating its own geometry with it, so the arrow is
   drawn instead: shaft at exactly 30, head symmetric about the shaft.

   A mask rather than an image, so it takes currentColor and matches whatever text it
   follows. Sized in em, so it scales with the type beside it.
   ------------------------------------------------------------ */
.arrow-out{
  display:inline-block;
  width:.74em;height:.427em;              /* sqrt 3 : 1, the system's proportion */
  margin-left:.42em;
  background:currentColor;
  -webkit-mask:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 6.93' fill='none' stroke='black' stroke-width='1.4' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M1.1,5.95 L10.000,0.8116'/%3E%3Cpath d='M6.400,0.8116 L10.000,0.8116 L8.200,3.9293'/%3E%3C/svg%3E") no-repeat center/100% 100%;
  mask:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 6.93' fill='none' stroke='black' stroke-width='1.4' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M1.1,5.95 L10.000,0.8116'/%3E%3Cpath d='M6.400,0.8116 L10.000,0.8116 L8.200,3.9293'/%3E%3C/svg%3E") no-repeat center/100% 100%;
}


/* ------------------------------------------------------------
   THE HERO MARK

   Wide enough for two columns, the mark sits beside the text and is the second thing you
   look at. Stacked into one column it lands underneath the buttons, where it reads as an
   unexplained illustration between the hero and the next section, and pushes everything
   below it down a screen.

   So on one column it goes behind the type as a watermark: large, faint, and out of the
   flow entirely, so it costs no vertical space. Faint enough that the headline keeps its
   contrast, which is the only constraint that matters here.

   `aria-hidden` and an empty alt already apply: it carries no information the words do not.
   ------------------------------------------------------------ */
.hero-mark{width:var(--mark-width);justify-self:center}

@media (max-width:899px){
  .hero-mark{
    position:absolute;
    top:50%;
    right:-8%;
    transform:translateY(-50%);
    width:88%;
    max-width:none;
    opacity:.10;
    pointer-events:none;
    z-index:0;
  }
}


/* tokens/effects.css */
:root{
/* Radii: demoted.
   The lattice needs square corners, so cards, panels and cells no longer round. Radius
   survives only where a control has to read as pressable. This is a deliberate trade: you
   cannot have a drawn grid and rounded cards without the grid looking accidental. */
--radius-sm:3px;   /* inputs */
--radius-md:4px;   /* buttons */
--radius-none:0;   /* cards, cells, panels. the default now. */

/* Shadows: near zero. Hairlines and the lattice do the work. */
--shadow-card:0 1px 2px rgba(13,27,42,.05);
--shadow-raised:0 2px 8px rgba(13,27,42,.08);

/* Motion: fades and small translations only. No bounces. */
--ease:cubic-bezier(.25,.6,.25,1);
--duration-fast:140ms;
--duration:240ms;
}
