/* ============================================================================
   HYDRO2050 - DESIGN TOKENS
   ----------------------------------------------------------------------------
   Source of truth: Paper file "Hydro 2050", page "Website".
   Every colour below carries its MEASURED contrast ratio as a comment. Those
   ratios are computed with the WCAG 2.1 relative-luminance formula by
   site/tools/contrast.mjs. None of them is copied from a brief. Eyeballing
   contrast has been wrong in both directions on this project before, and one
   brief circulated a wrong figure for turquoise on navy (claimed 4.04, actual
   5.89), so the rule is: recompute, never quote.

   AA thresholds:  4.5:1 normal text
                   3:1   large text (24px+, or 19px+ bold)
                   3:1   UI control boundaries and meaningful graphics
   ========================================================================== */

:root {

  /* --- BRAND COLOURS ------------------------------------------------------
     The client's real brand values, as carried by the Paper token set. Two of
     them cannot carry text at any size. That is a fact about the colours, so
     the system gives each one a defined job rather than discarding it.       */

  --brand-azure:   #00A0E0;  /* 2.96:1 on white -> fails even the 3:1 large
                                floor. SHAPES, WAVES AND FILLS ONLY.
                                3.25:1 on navy -> usable as a graphic edge.  */
  --brand-turq:    #23E1DC;  /* 1.63:1 on white -> shapes only on light.
                                5.89:1 on navy  -> safe as TEXT on navy.     */
  --brand-navy:    #00477B;  /* 9.60:1 on white, 8.80:1 on surface           */
  --brand-mid:     #4A90B8;  /* 3.52:1 on white -> large text / shapes only  */

  /* --- TEXT-SAFE DERIVATIVES ---------------------------------------------
     The brand azure darkened until it passes, hue kept. This is how a brand
     colour that fails contrast survives: derive a text-safe sibling and
     reserve the original for shapes.                                         */

  --azure-ink:     #0078A8;  /* 4.94:1 on white, 4.53:1 on surface. Clears the
                                4.5 body floor on both, with little slack.   */
  --azure-hover:   #00638B;  /* 6.65:1 on white                              */
  --brand-blue-cta:   #0A63AE;  /* white on it = 6.16:1                      */
  --brand-blue-cta-h: #084F8C;  /* white on it = 8.38:1                      */

  /* --- SURFACES ----------------------------------------------------------- */

  --page:          #FFFFFF;
  --surface:       #EBF7FD;  /* 1.09:1 against page. A tint, not a boundary. */
  --surface-navy:  #00477B;
  --surface-char:  #1F2937;

  /* --- INK ----------------------------------------------------------------- */

  --ink:           #1F2937;  /* 14.68:1 on page, 13.46:1 on surface          */
  --ink-muted:     #5A6B78;  /*  5.51:1 on page, 5.06:1 on surface          */
  /* The same muted role, darkened for type that sits over the brand's own
     dot and wave artwork rather than over a flat ground. Measured, not
     guessed: tools/over-image-contrast.mjs found the darkest pixel the dot
     field puts behind body copy on Page 08 at rgb(221,225,238), where
     --ink-muted is 4.22:1 and fails the 4.5 body floor. This is 5.46:1 on
     that same pixel, and 7.13:1 on page.                                    */
  --ink-muted-art: #4A5A66;
  --on-navy:       #FFFFFF;  /*  9.60:1 on navy                              */
  --on-navy-mute:  #BFDCEA;  /*  6.69:1 on navy                              */

  /* --- LINES ---------------------------------------------------------------
     Two border tokens on purpose. WCAG's 3:1 rule covers UI COMPONENT
     boundaries, not decorative dividers, so a soft rule between rows is
     allowed to be soft. An input's edge is not.                              */

  --rule:          #CFE6F5;  /* 1.29:1 on page. Decorative divider only.     */
  --border-input:  #5A6B78;  /* 5.51:1 on page. Real control boundaries.     */
  --focus:         #0078A8;  /* 4.94:1 on page, 4.53:1 on surface. Both clear
                                the 3:1 floor a focus ring has to meet.      */

  /* --- TYPE ----------------------------------------------------------------
     Montserrat for display, Source Sans 3 for body. These are the client's
     brand faces and they replace the Archivo / Inter Tight pairing used by
     the superseded mockup at the repository root. Loaded from Google Fonts
     for this localhost build; self-hosting is a launch follow-up.

     Sizes below are the distinct values measured across the Home and Case
     studies artboards, desktop and mobile. Where the design used two values
     within a pixel of each other, the build uses one.                        */

  --font-display: 'Montserrat', 'Helvetica Neue', Arial, sans-serif;
  --font-body:    'Source Sans 3', 'Helvetica Neue', Arial, sans-serif;

  /* Named by ROLE, not by a size ladder, because the design does not use a
     ladder: it uses a set of sizes each attached to one job. Naming them
     h1/h2/h3 would imply a relationship between them that the artboards do
     not have, and the first person to reuse --text-h3 for something that is
     not a card title would get the wrong number.

     Two consolidations, both listed in the build brief: the Industries tile
     title measured 25px against the card title's 21px and the closer's 26px,
     which is three sizes doing one job, so the tile keeps 25 and nothing else
     is added at 26; and every 20px/21px body measurement is served by one
     21px --text-lead. */

  /* THE SIZES ARE FLUID, AND THAT IS THE POINT.

     Every value below used to be the artboard's own pixel figure, held flat
     from 900 all the way to 2560 and then dropped to the 375 figure in one
     step at the breakpoint. At 1440 and at 375 that is correct and at every
     width between them it is not: the display size stood at 88px on a 772px
     column at 900, then fell to 34px one pixel later, a 2.6x step in the
     middle of a drag. Nothing caught it, because a font size cannot overflow
     anything and the harness only ever looked at 1440, 768 and 375.

     Each role is now a two-segment ramp, and the anchors are:

       375   the mobile artboard's measured value, unchanged
       900   the breakpoint, where the composition itself changes
       1440  the desktop artboard's measured value, unchanged

     This file carries the 900 -> 1440 segment. base.css carries the
     375 -> 900 one, inside the same @media the rest of the mobile design
     lives in, so the two meet at the breakpoint rather than stepping across
     it. Both resolve to the same number at 900, to within a rounding error,
     so a drag through the breakpoint moves type continuously.

     The 900 anchor is not invented. It is the desktop value scaled by the
     column: 772 / 1312 = 0.588, so 88 becomes 52, 60 becomes 36, 52 becomes
     31. Where that arithmetic lands below the mobile value the mobile value
     wins and the role is flat below 900 instead, which is why the band, tile,
     figure, lead and prose ramps start at their 375 figure.

     Reading sizes do not scale with the column and are left absolute:
     --text-body, --text-small and --text-caption. A caption is 13px because
     13px is readable, not because the artboard happens to be 1440 wide.

     The arithmetic for a segment running from `a` at 900 to `b` at 1440:
        slope = (b - a) / 540, expressed as vw, so (b - a) / 5.4
        base  = a - slope * 900
     Each line carries its own a and b. Above 1440 every clamp caps at the
     measured desktop value, because the content column caps at 1312 there and
     type that kept growing would walk out of it. */

  --text-display:  clamp(52px, calc(6.6667vw - 8px), 88px);  /* 52 -> 88 */
  --text-title:    clamp(36px, calc(4.4444vw - 4px), 60px);  /* 36 -> 60 */
  --text-section:  clamp(31px, calc(3.8889vw - 4px), 52px);  /* 31 -> 52 */
  --text-closer:   clamp(38px, calc(4.8148vw - 5.333px), 64px);  /* 38 -> 64 */
  --text-band:     clamp(22px, calc(2.2222vw + 2px), 34px);  /* 22 -> 34 */
  --text-tile:     clamp(22px, calc(0.5556vw + 17px), 25px);  /* 22 -> 25 */
  --text-card:     21px;  /* case study card title, 22 at 375, see base.css  */
  --text-stat:     clamp(56px, calc(7.4074vw - 10.667px), 96px);  /* 56 -> 96 */
  --text-stat-sm:  34px;  /* laboratory result figure, 34 at both anchors    */
  --text-figure:   clamp(22px, calc(1.1111vw + 12px), 28px);  /* 22 -> 28 */
  --text-lead:     clamp(17px, calc(0.7407vw + 10.333px), 21px);  /* 17 -> 21 */
  --text-body:     17px;  /* running body copy, absolute                     */
  --text-prose:    clamp(15px, calc(0.1852vw + 13.333px), 16px);  /* 15 -> 16 */
  --text-small:    15px;  /* directory links, figure panel label, absolute   */
  --text-caption:  13px;  /* eyebrow, image caption, legal strip, absolute   */

  /* TWO ROLES THE TOKEN SET WAS MISSING, retyped as literals in every sheet
     instead of named once here.

     --text-head is a page's own section heading, 34 / 42 on the artboards and
     22 / 28 at 375. It is written out as a literal in ten places across six
     sheets: partners.css, industries.css, contact.css three times, about.css,
     industry.css and how-it-works.css three times. It is NOT --text-band,
     which is the navy closing band's headline and carries a looser 46
     leading. The two share a size and nothing else, and folding them together
     is how a change to one silently moves the other.

     --text-copy is the running paragraph inside a content row, 18 / 30 on the
     artboards and 17 / 26 at 375, and it appears as a literal about fifteen
     times. It sits between --text-body at 17 and --text-lead at 21.

     Both ramp only above the breakpoint, so each floor is exactly the value
     the sheets' own mobile blocks already set, and a sheet that adopts one
     can delete its mobile override rather than restate it.                  */
  --text-head:     clamp(22px, calc(2.2222vw + 2px), 34px);  /* 22 -> 34 */
  --lh-head:       clamp(28px, calc(2.5926vw + 4.667px), 42px);  /* 28 -> 42 */
  --text-copy:     clamp(17px, calc(0.1852vw + 15.333px), 18px);  /* 17 -> 18 */
  --lh-copy:       clamp(26px, calc(0.7407vw + 19.333px), 30px);  /* 26 -> 30 */

  /* Line heights ramp with their own size, so the ratio the artboard drew is
     held at both anchors rather than only at one of them. */
  --lh-display:    clamp(54px, calc(7.0370vw - 9.333px), 92px);  /* 54 -> 92 */
  --lh-title:      clamp(39px, calc(4.6296vw - 2.667px), 64px);  /* 39 -> 64 */
  --lh-section:    clamp(38px, calc(4.6296vw - 3.667px), 63px);  /* 38 -> 63 */
  --lh-closer:     clamp(42px, calc(5.1852vw - 4.667px), 70px);  /* 42 -> 70 */
  --lh-band:       clamp(28px, calc(3.3333vw - 2px), 46px);  /* 28 -> 46 */
  --lh-tile:       clamp(27px, calc(0.7407vw + 20.333px), 31px);  /* 27 -> 31 */
  --lh-card:       28px;
  --lh-stat:       clamp(56px, calc(7.4074vw - 10.667px), 96px);  /* 56 -> 96 */
  --lh-stat-sm:    38px;
  --lh-figure:     clamp(28px, calc(1.1111vw + 18px), 34px);  /* 28 -> 34 */
  --lh-lead:       clamp(27px, calc(0.9259vw + 18.667px), 32px);  /* 27 -> 32 */
  --lh-body:       26px;
  --lh-prose:      clamp(23px, calc(0.1852vw + 21.333px), 24px);  /* 23 -> 24 */
  --lh-small:      22px;
  --lh-caption:    19px;

  --track-display: -0.04em;  /* 88px and up                                  */
  --track-title:   -0.035em; /* 60px                                         */
  --track-section: -0.028em; /* 52px                                         */
  --track-band:    -0.02em;  /* 25px to 34px                                 */
  --track-figure:  -0.01em;
  --track-eyebrow:  0.14em;

  /* Weight ceiling. Montserrat 600 is the heaviest weight this system uses.
     The design's headings read as authority through size and colour, not
     through mass, and 700+ Montserrat at 88px is a slab.

     The first pass recorded the Home hero tagline and intro card as dropped
     from 700 to 600. That was never done and, on review, should not be: Paper
     sets both at 700 and so does this build. DESIGN-NOTES says so under
     "Correction to the first pass's own notes", and this comment used to say
     the opposite, which left the file contradicting both itself and the code.
     Those two elements are the whole of the 700 exception. Anything else at
     700 is a defect: the hero's "Our partners" caption was one and is now 600.
  */
  --wt-light:   300;  /* the 60px and 96px display numerals only */
  --wt-regular: 400;
  --wt-medium:  500;
  --wt-semi:    600;
  --wt-bold:    700;  /* the hero tagline and intro card only, from Paper */

  /* --- GRID AND BLEED ------------------------------------------------------
     1312 content column inside a 1440 artboard, so 64px gutters either side.
     Type holds that gutter at every width. Photography is allowed to break it
     to 1376, which leaves a 32px margin, and a hero photograph runs off the
     page edge entirely on the side it bleeds toward.

     THE GUTTER IS FLUID, AND EVERY COLUMN ON THE SITE HANGS OFF IT.

     It used to be a flat 64 above the breakpoint and a flat 20 below, which
     meant --content was `100vw - 128px` above and `100vw - 40px` below. Those
     two do not meet: dragging from 900 to 899 WIDENED the content column from
     772 to 859, so the whole page jumped 87px outward as the window got
     narrower, and every element measured against the column jumped with it.
     It is the single largest discontinuity in the build and it is invisible
     at 1440, 768 and 375, which is every width this site was ever checked at.

     One ramp now runs the whole way, 20 at 375 to 64 at 1440, so the column
     interpolates through the breakpoint instead of stepping across it. Both
     design widths are hit exactly: 375 - 40 = 335 and 1440 - 128 = 1312.

     --bleed is the same shape. Its margin runs 0 at 375, where the mobile
     artboard puts photography edge to edge, to 32 at 1440, where it insets to
     1376. base.css no longer needs to override either one.

     Arithmetic, for a step running from `a` at 375 to `b` at 1440:
        slope = (b - a) / 1065  expressed as vw
        base  = a - slope * 375 expressed as px                             */

  --gutter:     clamp(20px, calc(4.507px + 4.1315vw), 64px);   /* 20 -> 64 */
  --bleed-gap:  clamp( 0px, calc(3.0047vw - 11.268px), 32px);  /*  0 -> 32 */
  --content: min(1312px, calc(100vw - var(--gutter) * 2));
  --bleed:   min(1376px, calc(100vw - var(--bleed-gap) * 2));
  /* --gutter-mob IS NOW THE SAME GUTTER, and that is deliberate.

     Ten rules across five sheets set a mobile block's horizontal padding from
     this token, all of them inside `@media (max-width: 899px)`, and all of
     them mean "put this full-bleed block back on the page's own margin". They
     were reading a literal 20 while `.wrap` above them had started ramping,
     so at 880 the closing band, the closer row, the plinth and the legal
     strip all sat at x20 against a content column at x41. Pointing the name
     at the ramp fixes every one of them without touching a sheet, and at 375
     it still resolves to exactly the 20 the mobile artboard draws.          */
  --gutter-mob: var(--gutter);

  /* --- SPACING -------------------------------------------------------------
     A 4px base. Only the steps the design actually uses are named.           */

  --s-1:   4px;
  --s-2:   8px;
  --s-3:  12px;
  --s-4:  16px;
  --s-5:  20px;
  --s-6:  24px;
  --s-8:  32px;
  --s-10: 40px;
  --s-12: 48px;
  --s-16: 64px;
  --s-20: 80px;
  --s-24: 96px;
  --s-30: 120px;

  /* --- RADII ---------------------------------------------------------------
     14px is the design's photograph radius. A hero bleeds right, so only its
     LEFT corners are rounded; a body image bleeds left, so only its RIGHT
     corners are. A photograph with four rounded corners is not in this design.
  */

  --r-photo:  14px;
  --r-card:   10px;
  --r-pill:  999px;
  --r-input:   6px;

  /* --- MOTION --------------------------------------------------------------
     Named so a duration can be changed in one place and so the reduced-motion
     block has something to collapse. The reveal rise is deliberately short:
     a long travel on a section that carries body copy makes the copy hard to
     start reading, which is the one thing motion must not cost here.         */

  --dur-fast:   140ms;  /* press feedback, must land inside 100-150ms        */
  --dur-hover:  200ms;  /* hover and focus transitions                       */
  --dur-reveal: 620ms;  /* scroll reveal fade and rise                       */
  --dur-drawer: 320ms;  /* mobile drawer open / close                        */
  --dur-slow:   700ms;  /* photograph scale on tile hover                    */

  --ease-out:   cubic-bezier(0.22, 0.61, 0.36, 1);
  --ease-inout: cubic-bezier(0.65, 0.05, 0.36, 1);

  --reveal-rise:   24px;  /* how far a revealing block travels               */
  --reveal-step:   70ms;  /* stagger between siblings in one section         */

  /* --- BREAKPOINT ----------------------------------------------------------
     900px, and it is measured rather than round. Below it the design is a
     different design, not a narrower one: the nav becomes a drawer, the case
     study rows drop their image band and figure panel and lead with the
     figure, the closing band's scrim rotates 90 degrees, and photography goes
     edge to edge instead of insetting. Those changes all belong to the same
     moment. 900 is where the 1312 column, scaled down, stops holding the
     three-up card grid at a readable card width (1312 / 3 = 437 at 1440;
     the same grid at 900 gives a 268px card, below the 300px the figure panel
     needs for its numeral and label to sit on one line).                     */

  --bp: 900px;
}
