/* ==========================================================================
   Prime Infoserv — design tokens
   Re-derived 2026-08-27 after review.

   WHAT CHANGED AND WHY — read this before editing anything below.

   The first derivation read the "Theme & Taste + Layout" reference as
   containing a dashed construction grid with small blue marker squares at
   the intersections. It does not. That screenshot was taken inside Figma:
   the dotted lines are Figma's layout guides and the blue square is a
   selection handle. Design-tool chrome was encoded as the project's primary
   dividing device and shipped across the homepage.

   Everything that followed from that error is gone: dashed section rules,
   marker squares, the boxed logo grid, and the tracked-out monospace
   micro-label that sat above every heading. The monospace face is removed
   from the system entirely — it was never asked for, it is not in any
   reference, and decorative mono is the most recognisable machine-made tell
   there is.

   What replaces them is derived from what the references actually show:
   division by colour field, large light display type, and open space.
   See system/ART-DIRECTION-PROTOCOL.md § Gate 0.5 and § Gate 0.6.
   ========================================================================== */

:root{

  /* ---- COLOUR --------------------------------------------------------
     The brand guideline (Input/Design System/Brand Colors.png) is
     AUTHORITATIVE FOR COLOUR. Transcribed exactly; not nudged for taste. */
  --navy:        #1B2A4A;
  --royal:       #2E5EA6;
  --red:         #C8102E;
  --steel:       #4A7FB5;
  --slate:       #5C6B7A;
  --silver:      #B0B8C1;
  --off:         #F4F5F7;
  --char:        #2D3436;
  --white:       #FFFFFF;

  /* CHARCOAL DEPTH SCALE — derived 2026-08-27 from the client's own art.
     The supplied hero (Home_Hero.png) and the three service renders sample
     at #101113–#202020: a near-black charcoal carrying only a whisper of
     blue, with a single electric-blue edge-glow as the sole accent. The
     client's instruction follows from it — "dark charcoal subtle gradient
     as prominent colour and not dark blue".

     The earlier navy→royal field was derived from a reference screenshot.
     This is derived from the artwork that will actually sit on the page,
     which is the stronger source. Blue is now a GLOW, not a field. */
  --char-950:    #0A0B0C;
  --char-900:    #121417;
  --char-800:    #1B1E22;
  --char-700:    #24282E;
  --navy-950:    #070C18;   /* retained for the footer only */

  --ink:         var(--char);
  --ink-strong:  var(--navy);
  --ink-soft:    var(--slate);
  --accent:      var(--royal);

  /* M1 — DIVISION BY COLOUR FIELD, NEVER BY A LINE.
     Three grounds and nothing else. A section is distinguished from its
     neighbour by which ground it sits on and by the space around it.
     There are no rules, dividers, dotted lines or borders between sections
     anywhere in this system. If you find yourself reaching for one, the
     spacing is wrong. */
  --ground:      var(--white);
  --ground-tint: var(--off);
  /* M4 — THE DEEP FIELD IS CHARCOAL, NOT BLUE.
     A near-vertical charcoal gradient, matched to the client's artwork so a
     supplied render sitting inside one of these sections shares its ground
     rather than floating on a different colour. Blue appears only as
     --glow: a soft, off-centre bloom at low opacity, echoing the single
     edge-light in the art. It is never a field and never a flat panel. */
  --ground-deep: linear-gradient(168deg,
                   var(--char-950) 0%, var(--char-900) 38%,
                   var(--char-800) 74%, var(--char-700) 100%);
  --glow:        radial-gradient(120% 90% at 78% 18%,
                   rgba(46,94,166,.30) 0%, rgba(46,94,166,.10) 34%, transparent 66%);

  /* Hairlines still exist, but only INSIDE a component where two pieces of
     content genuinely abut — a table body, a stacked list. Never between
     sections, never dashed, never dotted. */
  --hair:        rgba(27,42,74,.10);
  --hair-deep:   rgba(255,255,255,.14);

  /* M8 — the tile scrim. The service artwork is already near-black, so this
     is much lighter than a scrim over a photograph would be: it exists to
     seat the type, not to darken the image. */
  --scrim-tile:  linear-gradient(180deg, transparent 46%, rgba(10,11,12,.28) 66%, rgba(10,11,12,.88) 100%);

  /* SIGNAL RED — QUARANTINED. Client decision, 2026-08-27.
     Reserved for the incident-response / urgent-assistance path and nothing
     else. Permitted surfaces, exhaustively:
        .btn--urgent  .incident-bar  .hotline  .u-urgent  .route--urgent
        .incident  (the widget in the closing field)
        .irhero    (incident-response.html — the whole page is the path)
     Not a general CTA, not a hover state, not decoration, not an error
     colour. A red brand colour under a "no alarm imagery" brief survives by
     meaning exactly one thing. */
  --urgent:      var(--red);
  --urgent-ink:  var(--white);

  /* ---- TYPE ----------------------------------------------------------
     ONE FAMILY. Plus Jakarta Sans is client-specified (questionnaire Q15,
     with the Google Fonts URL) and binding.

     There is deliberately NO --font-mono. Monospace was a pipeline default
     that no reference supports and the client rejected on sight. Tabular
     figures come from font-variant-numeric, which is what it is for. */
  --font:  "Plus Jakarta Sans", ui-sans-serif, system-ui, -apple-system, sans-serif;

  /* M3 — DISPLAY IS LARGE AND LIGHT.
     The taste reference sets its display at a light weight and a very large
     size, with the tracking pulled in as the size grows. Weight, not size,
     is what separates its display from its body — and the display weight is
     LIGHTER than the body, which is the inverse of the default habit. */
  /* Reduced from 7rem after review: at the old size the hero headline
     filled the banner top to bottom and left no air under the masthead,
     which killed the composition the artwork was chosen for. The banner
     needs to read as a photograph with type in it, not as type on a
     background. */
  --fs-display: clamp(2.4rem, 4.6vw, 4.4rem);
  --fs-h2:      clamp(2rem, 4vw, 3.6rem);
  --fs-h3:      1.375rem;
  --fs-lead:    1.1875rem;
  --fs-body:    1rem;
  --fs-small:   .9375rem;
  --fs-micro:   .8125rem;

  --tr-display: -.03em;
  --tr-h2:      -.025em;
  --tr-h3:      -.012em;

  --fw-light:   300;   /* display, h2, large numerals */
  --fw-reg:     400;   /* body */
  --fw-med:     500;   /* h3, labels, nav */
  --fw-semi:    600;   /* buttons only */

  --lh-display: 1.0;
  --lh-h2:      1.06;
  --lh-body:    1.65;

  /* ---- RADIUS --------------------------------------------------------
     M2 (revised 2026-08-27, client instruction) — RADIUS 0 ON EVERYTHING.

     The earlier rule kept one exception: the pill button, derived from the
     Testimonials-2 reference where the "View Work" pill is the only rounded
     object in frame. That exception is withdrawn. With the charcoal artwork
     and the sharp-cornered type now carrying the page, a rounded control was
     the only soft object left and it read as borrowed from a different
     system rather than as a deliberate contrast.

     There is exactly one radius token and its value is zero. No --r-pill,
     no --r-card, and adding either is a defect. */
  --r-none:  0;

  /* ---- SPACE ---------------------------------------------------------
     With no rules to separate sections, SPACE IS THE DIVIDER — so it has to
     be generous enough to do that job. But the client asked for "balanced
     whitespace that makes every layout compact yet not overwhelming", and
     for Testimonials-2 specifically "more compact layout & less whitespace".
     Resolution: generous BETWEEN sections, tight WITHIN them. */
  --s-1: .25rem; --s-2: .5rem;  --s-3: .75rem; --s-4: 1rem;
  --s-5: 1.5rem; --s-6: 2rem;   --s-7: 3rem;   --s-8: 4rem;
  --s-9: 6rem;
  --pad-section: clamp(4.5rem, 9vw, 9rem);
  --shell-max:   1320px;
  --gutter:      clamp(1.25rem, 4.5vw, 3.5rem);

  /* ---- MOTION --------------------------------------------------------
     GSAP + ScrollTrigger, vendored locally at assets/js/vendor/.
     The client banned "excessive animation", so the rule is: motion
     clarifies arrival and state, and never decorates. Nothing bounces,
     nothing parallaxes, nothing counts up. Everything collapses under
     prefers-reduced-motion. */
  --dur-fast:  180ms;
  --dur-base:  320ms;
  --dur-slow:  620ms;
  --ease:      cubic-bezier(.22,.61,.24,1);

  --header-h:  76px;
}

/* ==========================================================================
   PROHIBITIONS — machine-checked in assets/js/verify.js.
   Each is the enforceable half of a mechanism. Breaking one silently
   reverts this project to the statistical centre it exists to avoid.

   P1  No box-shadow, anywhere, on anything. Depth comes from the colour
       field, never from a shadow.                                    (M1)
   P2  border-radius 0 on EVERY element without exception — structure,
       imagery, controls, badges. There is no rounded object anywhere in
       this system.                                                   (M2)
   P3  NO DASHED OR DOTTED BORDERS ANYWHERE. Not as section dividers, not
       inside components, not on hover. The device was an artefact of a
       Figma screenshot and it is the single most visible machine-made tell
       this project shipped.                     (Gate 0.5, Gate 0.6)
   P4  No rules between sections at all. Sections are divided by which
       ground they sit on and by the space around them.                (M1)
   P5  NO MONOSPACE. The family is not loaded and no token references it.
       Tabular figures use font-variant-numeric.                 (Gate 0.6)
   P6  NO TRACKED-OUT UPPERCASE MICRO-LABEL ABOVE HEADINGS. No kicker
       chips, no bullet squares, no dots before section titles. Section
       identity comes from the headline.                          (M5, Gate 0.6)
   P7  Logos sit in open space. No box, no border, no grid line around a
       logo, ever.                                              (M7, Gate 0.6)
   P8  One gradient direction and one hue pair: --ground-deep, near-vertical,
       navy to royal. No diagonal gradients. No gradient on a button. (M4)
   P9  Signal Red appears only on .btn--urgent, .incident-bar, .hotline,
       .u-urgent, .route--urgent, .incident and .irhero. On any content
       page that is two surfaces at most: the incident route in the router
       and the incident widget in the closing field. incident-response.html
       is the exception — the whole page is the incident path.
                                                        (client decision)
   P10 --steel never carries text below 24px (3.85:1). --silver never
       carries text on a light ground at any size.          (WCAG 2.2 AA)
   P11 No padlock, hooded figure, code-rain, circuit-board or alarm-glow
       imagery or iconography.
       NAMED EXCEPTIONS, both client-supplied and both deliberate:
         - the Prime logo contains a shield (brand equity, untouchable);
         - the supplied hero and the Managed SOC render contain a shield
           motif. The client chose this artwork. The prohibition therefore
           covers shields WE would introduce, not shields the client has
           commissioned. No shield may be drawn in CSS, in an icon, or in
           any asset we source ourselves.
   P14 The deep field is CHARCOAL. A navy or royal-blue field is a defect.
       Blue exists in a dark section only as --glow, at low opacity, and
       never as the section's ground.                                 (M4)
   P15 Logo marks are shown at their natural colour on a white ground.
       No greyscale filter, no tinted panel, no bordered cell. A logo with
       a white background must sit on white so the mark reads rather than
       the file.                                                (M7, client)
   P16 A PIN MUST NOT CROP ITS OWN CONTENT, and must clear the masthead.

       The original wording — "pins never begin at a heading" — was the
       right fix for the wrong reason. It came from the industries rail,
       where heading plus panel exceeded the viewport, so holding the
       heading at the top left too little room and every industry was cut
       off. The heading was not the problem; the height was.

       The real test is arithmetic: masthead + everything pinned + a
       comfortable margin must fit the shortest viewport the design
       supports. Where it does, pinning the heading with the component is
       better — the reader keeps the question in view while the answers
       advance. Where it does not, the heading scrolls away first.

       Measured on this page: the lifecycle pins its heading (628px of
       813px, fits); the industries rail does not (heading plus panel
       overflows, so the heading scrolls away).

   P17 A PINNED ELEMENT MUST NOT CHANGE SIZE WHILE PINNED. A panel that
       opens to `auto` sizes itself to its own copy, and unequal copy means
       the pinned block changes height mid-scroll, ScrollTrigger recomputes
       its end, and the page lurches. Reserve one height for every state.

   P18 A PAGE WITH MORE THAN ONE PIN MUST SET `refreshPriority` IN DOM
       ORDER, highest first. ScrollTrigger otherwise recalculates in
       creation order, so a pin created early but positioned late is
       measured against a page height that does not yet include the earlier
       pin's spacer — and the two ranges overlap. Both are machine-checked
       (`accordionHeightStable`, `pinsOverlap`).
   P12 No acronym without its business consequence in the same block.
   P13 Every card of the same type has the SAME resting state and the SAME
       hover state. A card that permanently displays what its siblings
       reveal on hover is a defect, not a highlight.                   (M8)
   ========================================================================== */
