/* ============================================================================
   IDEAL Project Consultants, design tokens.
   Single source of truth, generated from tokens.md. Locked 12 October 2026.
   Nothing in the pages hardcodes a colour, size or radius; everything reads
   from the variables below.
   ========================================================================= */
:root{
  /* 1. brand */
  /* 149: the anchor is now the charcoal out of the IDEAL mark itself. The
     letters I, D, E and L are #3C3C3C, sampled off image/logo2x.png where it
     is the dominant ink at 8,169 pixels. The site was running #1D1F17, a near
     black olive that matched nothing in the brand. */
  --brand-anchor:#3C3C3C;
  --brand-accent:#4A7020;

  /* 2. neutral ramp, five steps replacing 42 */
  --neutral-0:#FFFFFF;
  /* 74: the section ground leaves the green tinted grey for a plain one.
     #F1F2F6 is very slightly cool, blue 246 against red 241, which is a
     deliberate step away from the warm earth in the photography. */
  --neutral-50:#F1F2F6;
  --neutral-200:#DCDFD4;
  /* 45: a sixth neutral, and it earns its place. #DCDFD4 is the rule colour;
     using it as a surface was the mistake, because the green icons on it
     measure 4.28:1 and fail AA. This is the profile's own warm sand, sampled
     off page 4 of the company profile, and it measures 4.67:1. */
  --surface-band:#E8E8D8;
  /* 46 + 149: the green for dark grounds. It was #70A038 off the company
     profile's cover, which measured 5.37:1 on the old near black anchor. The
     charcoal anchor is lighter, so that same green falls to 3.56:1 and misses
     AA for the small type it carries, the topbar link and the dark eyebrow.
     Lightened to #86B83C, the same hue 82, which measures 4.69:1 on #3C3C3C.
     It fails on white at 2.35:1, so dark grounds only, as before. */
  --accent-on-dark:#86B83C;
  /* 67: the band gradient. The IDEAL mark runs #648F15 to #82B228 at hue 81,
     darker on the left and brighter on the right. Those exact values carry
     white type at only 3.83:1 and 2.52:1, so the band keeps the mark's hue and
     its direction but holds the lightness inside the legible range. Edges
     measure 7.09:1 and 4.63:1, the centre 5.79:1. */
  --band-edge-dark:#44630E;
  --band-edge-light:#5A8013;
  --band-gradient:linear-gradient(90deg,var(--band-edge-dark) 0%,
    var(--brand-accent) 30%,var(--brand-accent) 70%,var(--band-edge-light) 100%);
  /* nudged from #6B7263, which measured 4.46:1 on the new ground and missed AA */
  --neutral-500:#656C5D;
  --neutral-900:#3C4336;

  /* 3. state */
  --state-hover:#3A5819;
  --state-active:#3A5819;
  --state-focus:#3A5819;

  /* 4. roles */
  --bg:var(--neutral-0);
  --surface-soft:var(--neutral-50);
  --text-primary:var(--brand-anchor);
  --text-body:var(--neutral-900);
  --text-muted:var(--neutral-500);
  --text-on-accent:#FFFFFF;
  --border:var(--neutral-200);

  /* 5. type */
  --font-display:'Poppins',sans-serif;
  --font-body:'Roboto',sans-serif;
  /* 87: a micro step below the eyebrow, for the two places that are labels
     rather than text: the hero chip and the dark header band. */
  --text-micro:10px;
  --text-eyebrow:12px;
  --text-caption:14px;
  --text-body-size:16px;
  --text-body-lg:18px;
  --text-h4:20px; --text-item:18px;
  --text-h3:25px;
  --text-h2:31px;
  --text-h1:clamp(26px,6.6vw,39px);     /* 138: fluid. 39 at 591px and up */
  --text-display:clamp(31px,8.2vw,49px);/* 39 x 1.25, hero only. 49 at 598 up */

  /* 6. spacing, 5px unit, the template's native rhythm */
  --space-unit:5px;
  --space-1:5px; --space-2:10px; --space-3:15px; --space-4:20px;
  --space-6:30px; --space-8:40px; --space-12:60px; --space-18:90px;
  --section-y:60px;

  /* 7. layout */
  --container:1170px;
  --grid-gutter:30px;
  --header-h:130px;
  /* 68: one height for every image rail on the page, so the hero, the
     atmospheric band and the projects rail read as one component */
  --rail-h:clamp(300px,58svh,540px);   /* 127: taller. was clamp(260,50svh,460) */

  /* 8. shape */
  --radius:0;            /* 69: square corners on everything */
  --radius-full:50%;
  --border-width:1px;
}
@media (max-width:767px){ :root{ --section-y:40px; } }

/* ---------- 16, 17, 19: one green, one neutral ramp, one type scale -------- */

body{font-family:var(--font-body);font-size:var(--text-body-size);line-height:1.7;
  color:var(--text-body);background:var(--bg)}

/* ============================================================================
   38 to 42: THE HEADING BLUEPRINT.
   Five roles. Each has one size, one weight, one colour and one measure.
   Nothing outside these five is a heading.

   Rule 1  Headings are anchor ink. Always. Green belongs to the eyebrow, to
           links and to actions, nowhere else.
   Rule 2  On a green or photographic ground, everything is white. No third case.
   Rule 3  Every heading has a measure, as paragraphs already do. A heading that
           runs the full 1170 is not a heading, it is a line of text.
   ========================================================================= */

h1,h2,h3,h4,h5,h6,.heading-lg,.heading-lead,.title,.name,.dtile-name{
  font-family:var(--font-display);color:var(--text-primary);
  text-transform:none;margin-top:0}

/* role: display. The homepage hero and nothing else. 700, the top of the
   Poppins range, which is where the one display case belongs. */
.hero2-text h1,.heading-xl{font-size:var(--text-display);font-weight:700;
  letter-spacing:-.01em}
/* role: page title, one per page */
h1,.heading-lg,.banner-text h1,.banner-text h2{
  font-size:var(--text-h1);line-height:1.15;font-weight:600;max-width:26ch;
  letter-spacing:.01em}

/* role: section */
h2,.heading-lead{font-size:var(--text-h2);line-height:1.2;font-weight:600;
  max-width:24ch;letter-spacing:-.005em}

/* role: block. 400, not 500: only Poppins 400 and 600 are loaded, so a
   declared 500 was being drawn at 400 all along. */
h3{font-size:var(--text-h3);line-height:1.25;font-weight:400;max-width:28ch}

/* role: item. h5 and h6 are folded in rather than given sizes of their own */
/* role: item. 121: at 20/400 this was a shrunken Block, five pixels and no
   other difference. It is not a heading, it is a label on an object: a tile
   name, a person, a field. 18/700 uppercase with .06em says that. */
h4,h5,h6,.title,.name,.ploop-cap h4,
.feature .title,.feature-modern .title,.feature .fbox-over .title{
  font-size:var(--text-item);line-height:1.35;font-weight:700;max-width:30ch;
  text-transform:uppercase;letter-spacing:.06em}

/* a centred heading keeps its measure, it just centres it */
.center h1,.center h2,.center h3,.center h4,
h1.center,h2.center,h3.center,h4.center,
.hero2-text h1,.cta-sameline h3,.hband-inner h2{margin-left:auto;margin-right:auto}

/* rule 2: on a green or photographic ground, white */
.bg-primary h1,.bg-primary h2,.bg-primary h3,.bg-primary h4,
.hband-figs h1,.hband-figs h2,.hband-figs h3,.hband-figs h4,
.call-action.bg-primary h3,.banner-inner h1,.banner-inner h2,
.dtile-over .title,.dtile-over h4{color:#fff}

p{font-size:var(--text-body-size);line-height:1.7;color:var(--text-body)}
p.lead{font-size:var(--text-body-lg);line-height:1.65}
.small,.photo-caption p,.table,.register td,.register th{font-size:var(--text-caption)}

/* 33: one eyebrow treatment everywhere. 118: 700, not 600. Roboto ships
   400 and 700 only, so a declared 600 was already rounding up to 700. Small, fully uppercase, a little bolder,
   in the one green. The footer heading and the small labels join it. */
.heading-sm-lead,.footer-widget .wgs-title:not([class*="color-"]),
.wgs-title,.minih{font-size:var(--text-eyebrow);text-transform:uppercase;
  letter-spacing:.14em;font-weight:700;color:var(--brand-accent);
  margin:0 0 var(--space-3);font-family:var(--font-body);line-height:1.5;
  max-width:40ch}

/* colour consolidation: every green becomes the one green */
.bg-primary,.btn,.call-action.bg-primary,.section-projects.bg-primary{
  background-color:var(--brand-accent)}
/* ===========================================================================
   119: THE BUTTON SYSTEM. Eight signatures across nine pages became three
   roles and one compact size. Three text sizes, three weights, two cases and
   three border colours were all doing the same job.

   Primary    the action we want taken. Solid brand green.
   Secondary  the alternative. Outline in the brand green.
   Onward     moves through a sequence. Solid anchor ink, carries the mark.
   Compact    only where vertical room is fixed, which is the header band.

   On a green or dark ground every role reverses, by blueprint rule 2.
   ======================================================================== */
.btn{display:inline-flex;align-items:center;justify-content:center;
  gap:var(--space-3);border-color:var(--brand-accent);color:var(--text-on-accent);
  font-family:var(--font-body);font-size:var(--text-caption);font-weight:700;
  text-transform:none;letter-spacing:.02em;padding:var(--space-3) var(--space-6);
  border-radius:var(--radius);border-width:2px;border-style:solid;
  min-height:52px;line-height:1.2;text-align:center}
.btn:hover,.btn:focus{background-color:var(--state-hover);border-color:var(--state-hover);
  color:var(--text-on-accent)}
.btn.btn-outline{background:transparent;color:var(--brand-accent);
  border-color:var(--brand-accent)}
.btn.btn-outline:hover,.btn.btn-outline:focus{background:var(--brand-accent);
  color:var(--text-on-accent);border-color:var(--brand-accent)}
.btn.btn-alt,.btn.btn-outline.btn-alt{background:var(--brand-accent);
  border-color:var(--brand-accent);color:var(--text-on-accent)}
/* 120: THREE SIZES. Button widths ran 173, 178, 185, 190, 197, 240, 247, 249,
   298, 346 and 419px, because each one sized itself to whatever words it
   happened to carry. A button is a fixed object. Every label now fits the
   object, and a label that does not fit is a label problem.

     Small   200 x 48   the header band only, where vertical room is fixed
     Medium  240 x 52   the default, which is nearly everything
     Large   300 x 58   the hero pair and the page CTA band

   max-width equals min-width, so a long label wraps inside the button
   rather than stretching it. */
.btn{width:240px;min-height:52px}
.btn.btn-sm{width:200px;min-height:48px;font-size:var(--text-eyebrow);
  letter-spacing:.12em;text-transform:uppercase;
  padding:var(--space-2) var(--space-3)}
.btn.btn-lg{width:300px;min-height:58px}
/* the rail arrows are an icon control, not a button, and keep their square */
.rail-nav{width:52px;height:52px}
.color-primary,a{color:var(--brand-accent)}
a:hover,a:focus{color:var(--state-hover)}
.bg-light,.section-logos.bg-light,.band-soft{background-color:var(--surface-soft)}

/* 5 (UX principle): a visible focus ring on everything focusable */
a:focus-visible,button:focus-visible,input:focus-visible,select:focus-visible,
textarea:focus-visible,.btn:focus-visible{outline:2px solid var(--state-focus);
  outline-offset:2px}

/* 83: the template's base rule gives every img a 6px radius, so the rail frames
   were square containers holding rounded pictures. Images follow the one radius
   token like everything else. .team-photo img keeps its circle on specificity. */
img,.navbar-toggle,.icon-bar{border-radius:var(--radius)}

/* one radius */
.btn,.card,.feature.boxed,.fbox-photo,.cardshot,.form-control,.logo-item,
.tileshot,.capshot{border-radius:var(--radius)}
/* 92: the director portraits were the last round thing on the site */
.team-photo img{border-radius:var(--radius)}

/* 6: paragraphs within a block run to consistent measure */
.section-content p,.content p{max-width:62ch}

/* spacing rhythm on the 5px unit */
.section-pad{padding-top:var(--section-y);padding-bottom:var(--section-y)}
.section-pad-sm{padding-top:var(--space-8);padding-bottom:var(--space-8)}
.section-pad-md{padding-top:var(--space-12);padding-bottom:var(--space-12)}

/* 116: --space-5 was referenced three times and never existed, so each of
   those declarations was silently dropped. The references are corrected, and
   the step is added so the next one cannot fail quietly. */
:root{--space-5:25px}

/* ============================================================================
   131: THE TEXT BLUEPRINT. The heading blueprint settled six roles; everything
   that is not a heading had never been settled at all. A sweep of every text
   node on all nine pages found 45 distinct signatures: body copy at 16 and 14
   with four line heights and two colours, six variants of the eyebrow, a
   weight 300 that belongs to no role, and stat figures set in Roboto at 30
   and 23.2px, off every scale and in the wrong family.

   Six text roles. Nothing outside them.

   Lead     Roboto 18 / 400 / 1.65   the opening paragraph of a block
   Body     Roboto 16 / 400 / 1.70   everything else
   Caption  Roboto 14 / 400 / 1.70   metadata, lists, table cells, the footer
   Micro    Roboto 10 / 400 / 1.45   the top bar and image captions
   Eyebrow  Roboto 12 / 700 / .14em  uppercase, green, above a heading
   Figure   Poppins, a scale step    a number that is the point of its block
   ========================================================================= */
p.lead,.lead{font-size:var(--text-body-lg);font-weight:400;line-height:1.65;
  color:var(--text-body)}
.lead a{font-weight:400}
.small,.photo-caption p,.table,.register td,.register th,
.footer-widget a,.footer-widget li,.quals li,.feat-meta,.other-meta,
.sub-title,.bench-card .small,.gal-row .small{
  font-size:var(--text-caption);line-height:1.7}
figcaption,.topbar,.topbar a{font-size:var(--text-micro);line-height:1.45}
/* one eyebrow. These five were 12/600 or 14/600 with four different
   tracking values, all doing the eyebrow's job. */
.ph-eyebrow,.bench-disc,.minih,.register th,.facts th,.pj-link{
  font-family:var(--font-body);font-size:var(--text-eyebrow);font-weight:700;
  text-transform:uppercase;letter-spacing:.14em;line-height:1.5}
/* a figure is the point of its block, so it is set in the display face at a
   step of the scale, not in Roboto at whatever size it landed on */
.stat-fig,span.h2,span.h3,.creds b{font-family:var(--font-display);
  font-weight:600;letter-spacing:-.01em}
span.h2,.creds b{font-size:var(--text-h2)}
span.h3{font-size:var(--text-h3)}

/* ============================================================================
   135: THE MOTION SYSTEM. An audit of all nine pages found 11 transition
   signatures, 7 durations, 4 easing curves and 152 elements transitioning
   `all`. None of the `all` rules are ours; there are 12 of them in the
   template. `all` animates every property that can animate, including ones
   nobody intended, and the browser cannot optimise it.

   Three durations, one curve.

   Fast  150ms  a colour changing under the pointer
   Base  300ms  something appearing or disappearing
   Slow  600ms  something travelling across the page

   Four rules:
   1. Never `transition: all`. Name the properties.
   2. Only transform and opacity for anything that moves. They are the only
      two the browser can do without laying the page out again.
   3. Nothing fades in on scroll. It delays reading, which is the opposite of
      what someone checking whether you have built a sewer works needs.
   4. One signature effect. Here it is the mark's own arrowhead, which slides
      4px on an onward button and does nothing else.
   ========================================================================= */
:root{
  --ease:cubic-bezier(.4,0,.2,1);
  --t-fast:150ms; --t-base:300ms; --t-slow:600ms;
}

/* ============================================================================
   144 (D4): LINE HEIGHT, PINNED PER ROLE.
   The audit found 28 distinct text signatures where sizes and weights gave
   only about 13. The difference was line height drifting inside a single
   role: Roboto 14/400 at 1.70, 1.50, 1.43 and 1.40; Roboto 14/700 at five
   values; Poppins 31/600 at three. Each role carries one now.
   ========================================================================= */
:root{--lh-display:1.08; --lh-page:1.15; --lh-section:1.2; --lh-block:1.25;
      --lh-item:1.35; --lh-lead:1.65; --lh-body:1.7; --lh-caption:1.7;
      --lh-micro:1.45; --lh-eyebrow:1.5}
.hero2-text h1,.heading-xl{line-height:var(--lh-display)}
h1,.heading-lg,.banner-text h1,.banner-text h2{line-height:var(--lh-page)}
h2,.heading-lead{line-height:var(--lh-section)}
h3{line-height:var(--lh-block)}
h4,h5,h6,.title,.name,.ploop-cap h4,
.feature .title,.feature-modern .title,.feature .fbox-over .title{
  line-height:var(--lh-item)}
p{line-height:var(--lh-body)}
p.lead,.lead{line-height:var(--lh-lead)}
.small,.photo-caption p,.table,.register td,.register th,
.footer-widget a,.footer-widget li,.footer-widget p,.quals li,.feat-meta,
.other-meta,.sub-title,.bench-card .small,.gal-row .small,li{
  line-height:var(--lh-caption)}
figcaption,.topbar,.topbar a{line-height:var(--lh-micro)}
.heading-sm-lead,.wgs-title,.minih,.ph-eyebrow,.bench-disc,.pj-link,
.register th,.facts th,.hero-chip,.dtile-name,.fig-label{
  line-height:var(--lh-eyebrow)}
