/* =========================================================================
   ProArc — Design Tokens
   Authority: docs/ProArc-Typography-Guideline-v1.2.md (LOCKED, 28 Jul 2026)
              docs/ProArc-Typography-Guideline-v1.3.md (SIGNED, 31 Jul 2026)

   This file is the ONLY place a raw colour or size value may appear.
   Everything else in the codebase references these custom properties.

   Do not edit values here without a version bump of the guideline.

   R2 note: v1.3's headline is that the dark ground needs NO new colour.
   Every ratio it requires is already in the neutral ramp below (#000000
   surface-dark, #ffffff / #ededed / #a6a6a6 on dark, #595959 structural,
   #333333 decorative). A dark site that needs new greys is a dark site
   building hierarchy from opacity, which v1.2 §9.16 bans.
   ========================================================================= */

:root {
  /* ---------------------------------------------------------------------
     Families
     General Sans — Indian Type Foundry, ITF Free Font License
     IBM Plex Sans Arabic — IBM / Bold Monday, SIL OFL 1.1
     Inter is deliberately absent from the fallback chain.
     --------------------------------------------------------------------- */
  --font-latin:
    "General Sans",
    -apple-system, BlinkMacSystemFont,
    "Segoe UI", Roboto,
    "Helvetica Neue", Arial,
    sans-serif;

  --font-arabic:
    "IBM Plex Sans Arabic",
    "Noto Sans Arabic",
    "Geeza Pro", "Segoe UI",
    "Tahoma",
    sans-serif;

  /* Arabic runs 5% larger than Latin. Confirm with a 16/17px proof. */
  --arabic-scale: 1.05;

  /* ---------------------------------------------------------------------
     Weights
     --------------------------------------------------------------------- */
  --fw-light:    300; /* Latin only — Arabic maps this to 400 */
  --fw-regular:  400;
  --fw-medium:   500;
  --fw-semibold: 600;
  --fw-bold:     700;

  /* ---------------------------------------------------------------------
     Scale — desktop, Latin. Base 16px = 1rem.
     --------------------------------------------------------------------- */
  --fs-caption:  0.75rem;  /* 12px */
  --fs-metadata: 0.875rem; /* 14px */
  --fs-body:     1rem;     /* 16px */
  --fs-body-lg:  1.25rem;  /* 20px */
  --fs-h3:       1.5rem;   /* 24px */
  --fs-h2:       2rem;     /* 32px */
  --fs-h1:       3.25rem;  /* 52px */
  --fs-mega:     5.25rem;  /* 84px */

  /* The menu overlay's nav list. It cannot borrow --fs-h1 (that collapses to
     40px at 1023 and 34px at 767). v1.3 E13 and 09-menu.md §5 decide the
     value on measured metrics rather than taste: the four labels were
     rendered in real General Sans and CONTACT, not SERVICES, is the widest
     at 266.3px bold.

     🔴 IT IS NO LONGER FIXED ACROSS BREAKPOINTS — 21 Aug 2026 (XLI, Mahesh
     on his phone: the doors read crowded). It takes 44px at ≤1024. The old
     note said "375px carries the full scale — 266px of label against 327px
     of column — so there is no mobile collapse to design and none is
     wanted", and that was a claim about whether the labels FIT. They did fit
     and they still would: what was never asked is what 52px caps do to the
     air around them once the rows share the overlay's height. The reason the
     token was pinned is intact — the nav must not follow --fs-h1's collapse,
     and 44px is its own value, not H1's 34.

     🔴 IT STEPS AT 1024, WHICH IS THE LAYOUT PAIR AND NOT THE TYPE PAIR, AND
     THAT IS DELIBERATE. This project's two breakpoint pairs are 1024/780
     (layout and chrome) and 1023/767 (the type scale). This token belongs to
     the MENU COMPONENT, whose whole arrangement switches at 1025 —
     `.menu-overlay__regions` and `.menu-centre` are both keyed there. Keyed
     at 1023 instead, the single pixel at 1024 would put the overlay in its
     mobile arrangement wearing desktop's type, which is exactly the
     one-pixel sliver H4-c spent a session repairing. Choosing between the
     two existing pairs is not introducing a third. */
  --fs-menu-nav: 3.25rem;  /* 52px desktop; 44px at ≤1024, see below */

  /* ---------------------------------------------------------------------
     Line-height — Latin
     --------------------------------------------------------------------- */
  --lh-mega:      1;
  --lh-hero:      1.05;
  --lh-editorial: 1.15;
  --lh-h2:        1.2;
  --lh-h3:        1.3;
  --lh-body-lg:   1.5;
  --lh-body:      1.6;
  --lh-metadata:  1.65;
  --lh-caption:   1.5;
  --lh-nav:       1;

  /* ---------------------------------------------------------------------
     Tracking — Latin. Arabic is always 0, enforced below.
     --------------------------------------------------------------------- */
  --ls-hero:       -0.03em;
  --ls-editorial:  -0.005em;
  --ls-h2:         -0.02em;
  --ls-h3:         -0.015em;
  --ls-body-lg:    -0.005em;
  --ls-body:        0em;
  --ls-caption:     0.04em;
  --ls-meta-label:  0.02em;
  --ls-nav:         0.06em;

  /* ---------------------------------------------------------------------
     Measure
     ch units are unreliable for Arabic — Arabic measures are px.

     E11 (v1.3) — the measure token is not the measure.

     v1.2 §4.4 and §9 rule 3 require running prose to sit between 45 and
     68 characters. The tokens implemented that literally as 68ch / 60ch —
     but a `ch` is the advance width of the digit zero, 9.31px at 16px in
     General Sans, against ~7.5px for an average character in running
     English. Measured with Range.getClientRects() across seven widths,
     counting real line boxes rather than dividing height by line-height:
     1.245 real characters per `ch`, stable from 400px to 720px.

       --measure-body     68ch -> 633px -> 80-85 chars   corrected to 55ch
       --measure-body-lg  60ch -> 698px -> ~75 chars     corrected to 48ch

     Only the two prose maxima move. The floors over-deliver and are safe,
     and the display measures below them (h3/h2/hero/editorial/overlay)
     are short-line measures, not prose maxima — E11 leaves them alone.
     Narrows every prose column by about 19%.
     --------------------------------------------------------------------- */
  --measure-body:      55ch;
  --measure-body-lg:   48ch;
  --measure-h3:        45ch;
  --measure-h2:        28ch;
  --measure-hero:      20ch;
  --measure-editorial: 24ch;
  --measure-overlay:   18ch;
  --measure-body-ar:   620px;

  /* ---------------------------------------------------------------------
     Colour — neutral ramp. Ratios measured, WCAG relative luminance.
     --------------------------------------------------------------------- */
  --color-ink:               #111111; /* 18.88:1 on white  */
  --color-ink-secondary:     #595959; /*  7.00:1 on white  */
  --color-surface:           #ffffff;
  --color-surface-dark:      #000000; /* the wordmark's own field */
  --color-on-dark:           #ffffff; /* 21.00:1 — display type   */
  --color-on-dark-body:      #ededed; /* 17.94:1 — body, no halation */
  --color-on-dark-secondary: #a6a6a6; /*  8.63:1 on black  */
  --color-hairline:          #d6d6d6; /* non-text */
  --color-hairline-dark:     #333333; /* non-text */

  /* ---------------------------------------------------------------------
     Colour — validation signal ONLY. Never editorial, never decorative.
     The two are NOT interchangeable; each fails on the other's surface.
     --------------------------------------------------------------------- */
  --color-signal:         #b3261e; /* 6.54:1 on white. FAILS on black (3.21:1) */
  --color-signal-on-dark: #f2695c; /* 6.95:1 on black. FAILS on white (3.02:1) */

  /* ---------------------------------------------------------------------
     Overlay
     --------------------------------------------------------------------- */
  --scrim-min-opacity: 0.6; /* minimum across the WHOLE text box + 24px bleed */

  /* ---------------------------------------------------------------------
     Brand

     The min-width pair is §8's floor and stays as the record. The rendered
     size is a decision (Board 17, Session K, H1-a): at 96px the word
     "proarc" — the bottom half of the artwork — sets a 10.5px x-height,
     below the site's own 12px text floor. 160px is where the word reaches
     heading scale AND where §8's own clear-space rule (the greater of 24px
     and the word's cap height) overtakes the 24px floor — so both numbers
     are derived, not picked. Below 160 the cap height falls back under the
     floor and 24px governs again.

     ⏳ THE CAP-HEIGHT DERIVATION EXPIRED ON 20 AUG 2026 AND THE VALUE IS
     HELD, NOT RE-DERIVED. It read `size × 51/330` — the FIRST asset's
     letterform height over its canvas — giving 24.7 → 25. ProArc's masters
     measure `881/5793`, so the cap at 160 is **24.33** and §8's rule now
     yields 24.33 rather than 24.7. 25 is still correct in the sense that
     matters — the clause states a MINIMUM and 25 clears it — so the token
     is unchanged and no arrival moves.

     It is flagged rather than taken because --arrival-clearance below is
     built on this token × 2: re-deriving it to 24 shifts the arrival on
     every desktop page and moves p21's pins, which is a second change
     riding on the back of the logo swap. Mahesh rules on it separately.
     --------------------------------------------------------------------- */
  --logo-min-width-desktop: 96px;
  --logo-min-width-mobile:  80px;
  --logo-size-desktop:     160px;
  --logo-size-tablet:      128px;
  --logo-size-mobile:       96px;
  --logo-clear-space:       24px;
  --logo-clear-space-desktop: 25px; /* held — see the note above; the
                                       masters' cap at 160 is 24.33 */

  /* -----------------------------------------------------------------------
     THE FOOTER SIGNATURE (Mahesh, 21 Aug 2026). Three options were rendered
     on the live footer at 1440 — 96 at the head, 220 on the legal line's
     row, 900 as a band — and he took the 220. Seeing it built, he asked for
     it smaller and for it to link home, so the value is now 160.

     🔴 THAT IS THE SAME NUMBER AS --logo-size-desktop AND IT STILL GETS ITS
     OWN TOKEN, which is the opposite of what I wrote here this morning. The
     first note argued the two must not share a token because the chrome's
     160 is "a size for a mark met at ARRIVAL, over content, on a fixed
     layer" and this one closes the page from inside the apparatus. That
     reasoning survives the coincidence: the two values agree TODAY, and a
     shared token would mean the next tuning of either silently moved the
     other. A token records a decision, not a number — and these are two
     decisions that happen to have landed on one value.

     The mark is now a LINK HOME, so it is also the same KIND of object as
     the plate, which is a second reason the sizes converged rather than an
     argument for merging them.

     The steps down are the layout's own breakpoints, not the type system's,
     because this mark shares its row with a line that wraps: at 1024 the
     footer's gutters halve, and by 780 the row stacks. --------------------- */
  --logo-size-footer:      160px;
  --logo-size-footer-tablet: 128px;
  --logo-size-footer-mobile:  96px;
}

/* =========================================================================
   Arabic overrides
   ========================================================================= */

html:lang(ar),
[dir="rtl"] {
  font-family: var(--font-arabic);
  font-size: calc(1rem * var(--arabic-scale));

  --lh-mega:      1.2;
  --lh-hero:      1.25;
  --lh-editorial: 1.3;
  --lh-h2:        1.35;
  --lh-h3:        1.45;
  --lh-body-lg:   1.65;
  --lh-body:      1.75;
  --lh-metadata:  1.8;
  --lh-caption:   1.65;

  --fw-light: 400; /* Light is never used in Arabic */
}

/* letter-spacing on Arabic severs the connecting strokes.
   The !important is deliberate and is the only one in this system:
   a single inherited tracking value from a Latin component breaks
   Arabic sitewide, and the failure looks like a font bug. */
html:lang(ar) *,
[dir="rtl"] * {
  letter-spacing: 0 !important;
  text-transform: none;
  font-style: normal;
}

/* =========================================================================
   The menu's own step — 1024, not 1023, and it is the ONLY token here that
   moves on the layout pair. See --fs-menu-nav's note above: the overlay's
   whole arrangement switches at 1025, so its type has to switch with the
   arrangement rather than with the type scale, or the single pixel at 1024
   renders the mobile overlay in desktop's type.
   ========================================================================= */

@media (max-width: 1024px) {
  :root {
    --fs-menu-nav: 2.75rem;  /* 44px — tablet */
  }
}

/* 🔴 AND 32px ON THE PHONE — 21 Aug, chosen by Mahesh from three sizes
   rendered at 393 x 672, which is his device's REAL viewport rather than its
   screen. It steps at 780, the chrome's own mobile breakpoint, which the
   overlay already uses for its padding; tablet keeps 44 because 768 was
   never put in front of him and his instruction was "only on mobile".

   🔴 THIS INVERTS THE TOKEN'S ORIGINAL REASONING AND THAT SHOULD BE SAID
   OUT LOUD. --fs-menu-nav was pinned because "--fs-h1 collapses to 40px at
   1023 and 34px at 767" and the nav must not follow it down. At 32 the nav
   is now SMALLER than --fs-h1's mobile 34. The old argument was made from
   label metrics — whether CONTACT's 266px fits a 327px column — and it was
   right about that and silent about air. What decided this instead was
   three renders at the viewport the reader actually has, which is the
   better evidence: the doors share a 102px row each, and 52px caps filled
   them.

   📌 The nav no longer being the largest type on the site is a real
   consequence, not an oversight: Home's section markers are 34px here. If
   that reads wrong, it is a question about the overlay's register, not a
   reason to restore a size that was chosen against a screen height nobody
   has. */
@media (max-width: 780px) {
  :root {
    --fs-menu-nav: 2rem;  /* 32px — phone */
  }
}

/* =========================================================================
   Tablet — 768 to 1023px
   ========================================================================= */

@media (max-width: 1023px) {
  :root {
    --fs-mega:      3.75rem;  /* 60px */
    --fs-h1:        2.5rem;   /* 40px */
    --fs-h2:        1.75rem;  /* 28px */
    --fs-h3:        1.375rem; /* 22px */

    --lh-mega:      1.05;
    --lh-hero:      1.1;
    --lh-editorial: 1.18;
    --lh-h2:        1.22;

    --ls-hero:     -0.025em;
  }
}

/* =========================================================================
   Mobile — 767px and below
   Two intentional collapses. Do not "fix" them.
   ========================================================================= */

@media (max-width: 767px) {
  :root {
    --fs-mega:      2.125rem; /* 34px — Mega collapses into H1        */
    --fs-h1:        2.125rem; /* 34px                                  */
    --fs-h2:        1.625rem; /* 26px                                  */
    --fs-h3:        1.25rem;  /* 20px — collapses with Body Large      */

    --lh-mega:      1.15;

    /* 🔴 THE HERO OPENS TO 1.25 — 21 Aug 2026 (XLI, Mahesh on his phone:
       the opening reads crowded). Measured in INK rather than in leading,
       which is the only way this is legible: the caps are 24.5px tall at
       34px, and 1.15 leaves 14.6px between one cap bottom and the next cap
       top — 60% of a cap height, under a five-line block of uppercase 600
       running the full measure with negative tracking. At 1.25 the ink gap
       is 18.0px, 74% of a cap, and the block costs 18px more of the first
       screen.

       📌 IT IS A TOKEN THAT REACHES EXACTLY ONE ELEMENT ON THE SITE, and
       that was checked rather than assumed: --lh-hero is read by `h1` in
       base.css and by `.t-hero`, and every one of the site's 58 h1s carries
       a register class — 47 `.pd-name t-editorial`, four `.wk-verb`, and one
       each for services/contact/careers/ajman/about. `.t-hero` is used by
       one page. So the blast radius of this line is Home's opening sentence,
       and nothing else moves.

       ⚠️ --lh-mega stays 1.15 and that is now a VISIBLE difference rather
       than a shared value: --fs-mega and --fs-h1 both collapse to 34 here,
       so Home's opening and its section markers are the same size in
       different leadings. The markers run one or two lines where the opening
       runs five, which is the whole reason the leading matters at all. If
       they ever read as inconsistent, that is a question about `.t-marker`,
       not a reason to put this back. */
    --lh-hero:      1.25;
    --lh-editorial: 1.25;
    --lh-h2:        1.25;

    --ls-hero:     -0.02em;
    --ls-editorial: 0em;
    --ls-h2:       -0.015em;
    --ls-h3:       -0.01em;
    --ls-body-lg:   0em;
  }
}

/* =========================================================================
   Role classes
   Apply these rather than re-declaring size/weight/tracking per component.
   ========================================================================= */

.t-hero {
  font-size: var(--fs-h1);
  font-weight: var(--fw-bold);
  letter-spacing: var(--ls-hero);
  line-height: var(--lh-hero);
  max-inline-size: var(--measure-hero);
  text-transform: uppercase;
  color: var(--color-ink);
}

.t-editorial {
  font-size: var(--fs-h1);
  font-weight: var(--fw-light);
  letter-spacing: var(--ls-editorial);
  line-height: var(--lh-editorial);
  max-inline-size: var(--measure-editorial);
  color: var(--color-ink);
}

/* Mega Splash, hollow — the SECTION MARKER. P2-c, boarded at H5-b (3 Aug).

   §3's scale gives Mega Splash a size (84/60/34) and §7.6 a line-height, but
   §4's role table has NO Mega row — no tracking, no measure, no colour. The
   role has been a size without a specification, and since Home's rebuild it
   has had no surface either. This is its site.

   Tracking BORROWS --ls-hero rather than minting --ls-mega: 84 and 52 are the
   same display family and one is not optically far enough from the other to
   earn a second value. Minting one would be inventing a number the guideline
   never set. Weight is 700 from §2's weight table, which does name Mega. */
.t-marker {
  font-size: var(--fs-mega);
  font-weight: var(--fw-bold);
  letter-spacing: var(--ls-hero);
  line-height: var(--lh-mega);
  text-transform: uppercase;
  color: var(--color-ink);
}

/* The hollow fill, and the @supports is load-bearing rather than defensive:
   an unsupported -webkit-text-stroke leaves `color: transparent` standing, so
   the failure is an INVISIBLE heading, not a solid one — total and silent.
   Inside the query the fill only goes transparent where the stroke paints. */
@supports (-webkit-text-stroke: 1px currentcolor) {
  .surface-dark .t-marker {
    -webkit-text-stroke: 1px var(--color-on-dark);
    color: transparent;
  }
}

/* §3.4: "Below 768px there is no Mega Splash", and any layout depending on
   Mega reading differently from H1 must be REDESIGNED, not rescaled. So the
   hollow goes with the size: at 34px a 1px stroke is a grey suggestion of a
   word rather than a marker, and the counters close up. The register resolves
   to solid — which is what H1 would have been. Placed after the @supports
   block deliberately; both selectors carry the same specificity, so this one
   wins on source order and nothing here depends on !important. */
@media (max-width: 767px) {
  .surface-dark .t-marker {
    -webkit-text-stroke-width: 0;
    color: var(--color-on-dark);
  }
}

.t-h2 {
  font-size: var(--fs-h2);
  font-weight: var(--fw-semibold);
  letter-spacing: var(--ls-h2);
  line-height: var(--lh-h2);
  max-inline-size: var(--measure-h2);
  color: var(--color-ink);
}

.t-h3 {
  font-size: var(--fs-h3);
  font-weight: var(--fw-semibold);
  letter-spacing: var(--ls-h3);
  line-height: var(--lh-h3);
  max-inline-size: var(--measure-h3);
  color: var(--color-ink);
}

.t-body-lg {
  font-size: var(--fs-body-lg);
  font-weight: var(--fw-light);
  letter-spacing: var(--ls-body-lg);
  line-height: var(--lh-body-lg);
  max-inline-size: var(--measure-body-lg);
  color: var(--color-ink);
}

.t-body {
  font-size: var(--fs-body);
  font-weight: var(--fw-regular);
  letter-spacing: var(--ls-body);
  line-height: var(--lh-body);
  max-inline-size: var(--measure-body);
  text-align: start;
  color: var(--color-ink);
}

/* Inline emphasis is WEIGHT ONLY. No colour. */
.t-body b,
.t-body strong {
  font-weight: var(--fw-semibold);
  color: inherit;
}

.t-caption {
  font-size: var(--fs-caption);
  font-weight: var(--fw-medium);
  letter-spacing: var(--ls-caption);
  line-height: var(--lh-caption);
  color: var(--color-ink-secondary);
}

/* Eyebrow: rule mark replaces the accent colour. Never a pill. */
.t-eyebrow {
  display: flex;
  align-items: center;
  gap: 12px;
  font-size: var(--fs-caption);
  font-weight: var(--fw-medium);
  letter-spacing: var(--ls-caption);
  line-height: var(--lh-caption);
  text-transform: uppercase;
  color: var(--color-ink-secondary);
}

.t-eyebrow::before {
  content: "";
  inline-size: 24px;
  block-size: 1px;
  flex: none;
  background: var(--color-ink);
}

.t-meta-label {
  font-size: var(--fs-metadata);
  font-weight: var(--fw-medium);
  letter-spacing: var(--ls-meta-label);
  line-height: var(--lh-metadata);
  text-align: start;
  color: var(--color-ink-secondary);
}

.t-meta-value {
  font-size: var(--fs-metadata);
  font-weight: var(--fw-regular);
  line-height: var(--lh-metadata);
  text-align: start;
  color: var(--color-ink);
}

.t-nav {
  font-size: var(--fs-metadata);
  font-weight: var(--fw-medium);
  letter-spacing: var(--ls-nav);
  line-height: var(--lh-nav);
  text-transform: uppercase;
  color: var(--color-ink);
}

/* Active state = weight + underline. No colour. */
.t-nav[aria-current] {
  font-weight: var(--fw-bold);
  text-decoration: underline;
  text-decoration-thickness: 2px;
  text-underline-offset: 6px;
}

html:lang(ar) .t-nav {
  font-weight: var(--fw-semibold); /* compensates for no uppercase */
  text-transform: none;
}

/* =========================================================================
   Dark surfaces
   ========================================================================= */

.surface-dark {
  background: var(--color-surface-dark);
  color: var(--color-on-dark-body);
}

.surface-dark .t-hero,
.surface-dark .t-editorial,
.surface-dark .t-h2,
.surface-dark .t-h3 {
  color: var(--color-on-dark);
}

.surface-dark .t-body,
.surface-dark .t-meta-value {
  color: var(--color-on-dark-body);
}

.surface-dark .t-caption,
.surface-dark .t-eyebrow,
.surface-dark .t-meta-label {
  color: var(--color-on-dark-secondary);
}

.surface-dark .t-eyebrow::before {
  background: var(--color-on-dark-secondary);
}

/* =========================================================================
   Text over imagery
   Default is the solid panel. Scrim is the fallback only.
   ========================================================================= */

.overlay-panel {
  background: var(--color-surface-dark);
  color: var(--color-on-dark);
  padding: 48px;
  max-inline-size: var(--measure-overlay);
}

@media (max-width: 1023px) { .overlay-panel { padding: 32px; } }
@media (max-width:  767px) { .overlay-panel { padding: 24px; } }

/* Scrim must hold >=60% black across the WHOLE text box plus 24px bleed.
   A gradient that fades to nothing behind the words fails WCAG. */
.overlay-scrim {
  position: relative;
  color: #fff; /* pure white only — never --color-on-dark-body over a scrim */
}

.overlay-scrim::before {
  content: "";
  position: absolute;
  inset: -24px;
  background: linear-gradient(
    to bottom,
    rgb(0 0 0 / 0%) 0%,
    rgb(0 0 0 / var(--scrim-min-opacity)) 18%,
    rgb(0 0 0 / var(--scrim-min-opacity)) 100%
  );
  z-index: 0;
}

.overlay-scrim > * {
  position: relative;
  z-index: 1;
}

/* =========================================================================
   Form validation — the ONLY place colour appears
   Colour is never the sole signal: text string + rule accompany it.
   ========================================================================= */

.field-error {
  font-size: var(--fs-metadata);
  font-weight: var(--fw-medium);
  line-height: var(--lh-metadata);
  color: var(--color-signal);
}

/* THE 2px RULE IS DRAWN IN THE MARGIN, NOT ON THE BOX — corrected by the
   forms phase (10-forms.md §4), which is the first thing ever to switch
   this class on.

   As authored it was `border-inline-start: 2px solid`, and switched on it
   MOVES THE FIELD THE READER IS READING: a border on the wrapper pushes
   its content in by 2px, and the padding that would keep the rule off the
   text pushes it further. A state must not shift the thing it describes,
   and a field that jumps sideways at the moment it is called wrong is the
   worst place on the site to do it.

   The pseudo-element occupies no layout at all, so an invalid field sits
   exactly where a valid one does. inset-inline-start is logical, so the
   rule moves to the other margin in RTL with everything else, and
   --gap-inline keeps it clear of the 20px mobile gutter.

   Same class, same three signals (§1.5: colour + string + rule), no
   movement. Same family as E6.1 — a rule that was written down and never
   rendered. */
.field-invalid {
  position: relative;
}

.field-invalid::before {
  content: "";
  position: absolute;
  inset-block: 0;
  inset-inline-start: calc(-1 * var(--gap-inline));
  inline-size: 2px;
  background: var(--color-signal);
}

.surface-dark .field-error { color: var(--color-signal-on-dark); }
.surface-dark .field-invalid::before { background: var(--color-signal-on-dark); }

/* =========================================================================
   Global guards
   ========================================================================= */

body {
  font-family: var(--font-latin);
  font-size: var(--fs-body);
  line-height: var(--lh-body);
  color: var(--color-ink);
  background: var(--color-surface);
  text-align: start;
}

/* Content type is never italic. The oblique belongs to the wordmark. */
h1, h2, h3, h4, h5, h6, p, li, td, th, figcaption, label, a {
  font-style: normal;
}

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
  }
}
