/* ============================================================
   RMS Automation — shared shell
   Palette sampled directly from the hero footage:
   charcoal desk, amber scan blade, cyan data trace, paper white.
   ============================================================ */

:root{
  --void:    #0A0B0C;
  --graphite:#131618;
  --steel:   #1C2124;
  --edge:    #262C30;
  --arc:     #FF8A1F;   /* the scan blade  — energy */
  --arc-dim: #B35F12;
  --plasma:  #4ADBEE;   /* the data trace  — intelligence */

  /* The third glow hue, and the one colour here not sampled from the
     footage. The pricing buttons need three orbits that read as peers, and
     two accents cannot make three: any neutral third is either brighter
     than --arc and --plasma or duller than both, so it either dominates the
     row or looks switched off. Violet is far enough from either to be told
     apart at a glance and close enough in chroma to carry the same weight.
     Glow only — it is not an accent and nothing else should reach for it. */
  --ion:     #9C7CF4;

  /* Brand gold — the logo only. Deliberately lower-chroma than --arc so
     the mark sits in the same hue family as the amber UI accents without
     competing with them for attention. Do not use these for UI. */
  --gold-lt: #F4D98B;
  --gold:    #E8A93C;
  --gold-dk: #C97F1E;
  --gold-cap:#B08A45;   /* wordmark caption — 6.2:1 on --void */
  --bone:    #ECE8E1;   /* the paper */
  --ash:     #7E868C;
  --ash-dim: #4C5459;

  --display: "Archivo", system-ui, sans-serif;
  --body:    "Inter Tight", system-ui, sans-serif;
  --mono:    "JetBrains Mono", ui-monospace, monospace;
  /* The nav lockup, and only the nav lockup. Kept separate from --display
     so that retuning the brand cannot reach into headings, and so the one
     place that uses it stays findable. Orbitron is a squared geometric
     face: flat-topped A on a low crossbar, squared bowls, uniform stroke.
     It has a wght axis and no wdth axis, so anything switching to it must
     clear the "wdth" setting Archivo left behind rather than inherit a
     value the font cannot honour.

     The oversized footer mark stays Archivo — see .foot-mark for why. This
     token is not a "brand font" to be applied wherever the brand appears;
     it survived at 17px and did not at 11.7vw. */
  --logo:    "Orbitron", var(--display);

  --gut: clamp(20px, 5vw, 64px);
  --max: 1240px;
}

*,*::before,*::after{ box-sizing:border-box; }

/* scroll-padding-top clears the fixed nav on anchor jumps. It matters more
   now that the bar retracts on the way down: jumping UP to a section brings
   the bar back, and without this it would land on top of the heading you
   just jumped to. A few px over the 64px bar so the heading is not flush
   against it. */
html{ scroll-behavior:smooth; scroll-padding-top:80px; -webkit-text-size-adjust:100%; }

body{
  margin:0;
  background:var(--void);
  color:var(--bone);
  font-family:var(--body);
  font-size:16px;
  line-height:1.6;
  -webkit-font-smoothing:antialiased;
  overflow-x:hidden;
}

img,canvas,video{ display:block; max-width:100%; }
a{ color:inherit; text-decoration:none; }

::selection{ background:var(--arc); color:var(--void); }

:focus-visible{
  outline:2px solid var(--plasma);
  outline-offset:3px;
  border-radius:2px;
}

.shell{ width:100%; max-width:var(--max); margin-inline:auto; padding-inline:var(--gut); }

/* ---------- eyebrow / label utility ---------- */
.eyebrow{
  font-family:var(--mono);
  font-size:11px;
  letter-spacing:.22em;
  text-transform:uppercase;
  color:var(--arc);
  display:flex;
  align-items:center;
  gap:10px;
  margin:0 0 20px;
}
.eyebrow::before{
  content:"";
  width:22px; height:1px;
  background:var(--arc);
  flex:none;
}

/* ============================ NAV ============================ */
.nav{
  position:fixed; inset:0 0 auto 0; z-index:90;
  height:64px;
  display:flex; align-items:center;
  background:rgba(10,11,12,.62);
  backdrop-filter:blur(18px) saturate(140%);
  -webkit-backdrop-filter:blur(18px) saturate(140%);
  border-bottom:1px solid transparent;
  transition:transform .3s cubic-bezier(.4,0,.2,1), border-color .3s, background .3s;
}
.nav.is-stuck{
  border-bottom-color:var(--edge);
  background:rgba(10,11,12,.9);
}
/* Scrolling down retracts the bar; scrolling up brings it straight back.
   js/nav.js owns the class. -100% rather than -64px so the bar can change
   height at a breakpoint without this needing to know. It clears its own
   bottom border too, which a -64px would leave as a hairline on screen. */
.nav.is-hidden{ transform:translateY(-100%); }
.nav .shell{ display:flex; align-items:center; justify-content:space-between; gap:24px; }

.brand{ display:flex; align-items:center; gap:11px; flex:none; }

/* ---------- the mark ----------
   A gold disc with a bolt struck across it. The bolt is knocked OUT, not
   painted on: disc and bolt are one evenodd path in assets/mark.svg, so the
   overlap cancels and the page shows through the bolt. The bolt is taller
   than the disc, so its tip escapes past the top edge and reads as gold
   there — that overhang is what makes it a bolt struck ACROSS the disc
   rather than one sitting inside it.

   It is a background image rather than inline SVG so that the eight places
   that render the brand keep shipping their bare `<span class="mark">` with
   no markup change. The url is resolved against this stylesheet, not the
   document, so the legal pages one directory down get it right for free.

   Colour lives in the SVG, not in the gold tokens below, because a knockout
   needs real transparency and a CSS gradient cannot punch a hole in itself.
   Retune the two together. */
.brand .mark{
  /* the artwork is taller than wide by exactly the bolt's overshoot:
     75.72 / 64 of the disc diameter */
  width:26px; height:30.8px; flex:none;
  background:url("../assets/mark.svg") center / contain no-repeat;
  /* the disc centre sits 57.7% down the artwork, so the box is nudged up to
     put the disc — the visual mass — on the row's centre line */
  transform:translateY(-2.4px);
  /* drop-shadow, not box-shadow: it follows the alpha instead of boxing the
     whole span, so the knockout stays clean */
  filter:drop-shadow(0 2px 7px rgba(232,169,60,.42));
}

.brand .word{
  font-family:var(--logo);
  /* Orbitron has a wght axis and NO wdth axis. Archivo's "wdth" 118 would
     simply be dropped, but "wght" 800 would still apply and land a weight
     far heavier than this face wants — so the axis list is cleared outright
     and the weight is set the ordinary way instead.

     500 at 17px with .14em of tracking measures 51px against the 48px the
     Archivo setting made, so the lockup keeps its width and the nav does
     not reflow. The tracking is not decoration: this is a squared geometric
     face and it needs the air to stay legible at 17px. */
  font-variation-settings:normal;
  font-weight:500;
  font-size:17px; letter-spacing:.14em;
  text-transform:uppercase;
  /* gold leaf on the RMS itself, brightest at the top of the letterform */
  background:linear-gradient(180deg, var(--gold-lt) 0%, var(--gold) 55%, var(--gold-dk) 100%);
  -webkit-background-clip:text;
  background-clip:text;
  color:transparent;
}
/* if the text-clip can't be honoured, fall back to flat gold rather than
   painting the wordmark in transparent ink */
@supports not ((-webkit-background-clip:text) or (background-clip:text)){
  .brand .word{ color:var(--gold-lt); background:none; }
}
.brand .word em{
  font-style:normal;
  font-family:var(--mono);
  font-variation-settings:normal;
  font-weight:400;
  font-size:10px;
  letter-spacing:.2em;
  color:var(--gold-cap);
  display:block;
  margin-top:-3px;
  /* the caption is its own colour, not part of the clipped gradient above */
  background:none;
  -webkit-text-fill-color:var(--gold-cap);
}

.nav-links{ display:flex; align-items:center; gap:28px; }
/* :not(.btn) so this doesn't out-specify .btn-arc's own colour — a bare
   `.nav-links a` (0,1,1) beats `.btn-arc` (0,1,0) and was painting the
   nav CTA's label ash-grey on orange. */
.nav-links a:not(.btn){
  position:relative;
  font-size:13.5px; font-weight:500; color:var(--ash);
  transition:color .2s;
}
.nav-links a:not(.btn):hover{ color:var(--bone); }

/* A hairline in the buy colour under the word. It wipes in from the left
   and collapses out to the RIGHT — the origin swaps between the two states,
   so leaving a link continues the movement instead of rewinding it, and a
   pointer travelling along the row hands off in one direction.

   Inset to the text box rather than a padded hit area, so the rule is
   exactly as wide as the word it belongs to and the row's 28px gaps stay
   readable as gaps.

   Hover only, deliberately. Keyboard focus already gets the global plasma
   ring at outline-offset:3px, and this rule sits below that line — the two
   together would read as two competing marks on one link rather than one
   focused link. .flip and .shift do take :focus-visible, but those live
   inside a pill the ring wraps whole; this one falls outside it. */
.nav-links a:not(.btn)::after{
  content:""; position:absolute; left:0; right:0; bottom:-7px; height:1px;
  background:var(--arc);
  transform:scaleX(0); transform-origin:right;
  transition:transform .34s cubic-bezier(.2,.7,.3,1);
}
.nav-links a:not(.btn):hover::after{
  transform:scaleX(1); transform-origin:left;
}

/* Pill CTAs. Fully-round ends plus a coloured drop-glow underneath so the
   button floats off the page rather than sitting flat on it. The face stays
   a flat --arc fill — a gradient washed the amber out at the top edge. */
.btn{
  display:inline-flex; align-items:center; justify-content:center; gap:8px;
  font-family:var(--body); font-size:13.5px; font-weight:600;
  padding:10px 22px;
  border:1px solid var(--edge);
  border-radius:999px;
  color:var(--bone);
  background:transparent;
  cursor:pointer;
  transition:border-color .2s, background .2s, color .2s,
             box-shadow .25s, transform .25s;
}
.btn:hover{
  border-color:var(--ash);
  background:rgba(236,232,225,.05);
}

.btn-arc{
  background:var(--arc); border-color:var(--arc); color:var(--void);
  box-shadow:
    0 2px 8px rgba(255,138,31,.26),
    0 10px 26px -8px rgba(255,138,31,.5);
}
.btn-arc:hover{
  background:#FFA047; border-color:#FFA047;
  box-shadow:
    0 3px 10px rgba(255,138,31,.34),
    0 14px 32px -8px rgba(255,138,31,.62);
  transform:translateY(-1px);
}
.btn-arc:active{ transform:translateY(0); }

/* The same button in --plasma. Kept to places that lead somewhere rather
   than commit to something: --arc is the buy colour and stays the buy
   colour, so a page with one of each does not present two equal offers.

   Specificity note — this ties .btn:hover at (0,2,0), so it only wins on
   source order. It has to stay below .btn-arc, not above it. */
.btn-plasma{
  background:var(--plasma); border-color:var(--plasma); color:var(--void);
  box-shadow:
    0 2px 8px rgba(74,219,238,.24),
    0 10px 26px -8px rgba(74,219,238,.45);
}
.btn-plasma:hover{
  background:#6BE5F4; border-color:#6BE5F4;
  box-shadow:
    0 3px 10px rgba(74,219,238,.32),
    0 14px 32px -8px rgba(74,219,238,.58);
  transform:translateY(-1px);
}
.btn-plasma:active{ transform:translateY(0); }

.btn-lg{ font-size:15px; padding:15px 30px; }

@media (prefers-reduced-motion:reduce){
  .btn-arc:hover{ transform:none; }
  .btn-plasma:hover{ transform:none; }
  /* js/nav.js already leaves the bar alone under reduced motion — a nav that
     vanishes without the slide is worse than one that just stays. This is
     the belt to that braces. */
  .nav{ transform:none !important; }
  /* The rule still has to say which link the pointer is on; what goes is
     the wipe. It lands at full width instead of drawing itself. */
  .nav-links a:not(.btn)::after{ transition:none; }
}

/* ---------- label that flips up on hover ----------
   Two stacked copies of the label inside a clipped box. Hovering slides
   the pair up by exactly one line, so the first copy exits through the
   top edge as the second arrives from the bottom. The second copy is
   aria-hidden so assistive tech reads the label once. */
/* 1.6em matches the body line-height the plain-text buttons inherit, so a
   flip button ends up exactly as tall as its non-flip siblings in a row. */
.flip{
  display:block;
  overflow:hidden;
  height:1.6em;
}
.flip span{
  display:block;
  height:1.6em;
  line-height:1.6em;
  transition:transform .38s cubic-bezier(.2,.7,.3,1);
}
.btn:hover .flip span,
.btn:focus-visible .flip span{ transform:translateY(-100%); }

@media (prefers-reduced-motion:reduce){
  .btn:hover .flip span,
  .btn:focus-visible .flip span{ transform:none; }
}

/* ---------- arrow that hands over on hover ----------
   The horizontal cousin of .flip, and the same trick: a box clipped to one
   arrow with two arrows in it. Hovering slides the pair one slot right, so
   the arrow on screen shoots out through the right edge while its
   replacement arrives from the left and settles where the first one was.

   Both arrows are pseudo-elements, so the button needs one empty span and
   no glyph in the markup — the arrow is decoration and belongs to the
   stylesheet, not to the sentence a screen reader announces. */
/* Direction is a vector, not a second copy of the mechanic. --sx/--sy say
   where the resting arrow exits; the replacement always waits at exactly
   the negative of that, so it arrives along the same line the first one
   left on and the pair reads as one arrow being pushed through. Point the
   glyph the same way and the motion looks like the arrow's own travel
   rather than a slide that happens to be nearby.

   The offsets are em rather than percentages because the box is taller
   than it is wide (1.6em against 1.1em) — a diagonal built from
   translate(100%,-100%) would travel further vertically than horizontally
   and land off the 45° the glyph is drawn on. Equal em values keep the
   path parallel to the arrow. Clipping still holds because clearing the
   box on either axis alone is enough to hide it. */
.shift{
  --sx:1.1em; --sy:0em;
  position:relative; display:block; flex:none;
  width:1.1em; height:1.6em; overflow:hidden;
}
.shift::before,
.shift::after{
  content:var(--glyph, "→");
  position:absolute; inset:0;
  line-height:1.6em; text-align:center;
  transition:transform .38s cubic-bezier(.2,.7,.3,1);
}
/* waiting one slot back along the travel line */
.shift::after{ transform:translate(calc(var(--sx) * -1), calc(var(--sy) * -1)); }
.btn:hover .shift::before,
.btn:focus-visible .shift::before{ transform:translate(var(--sx), var(--sy)); }
.btn:hover .shift::after,
.btn:focus-visible .shift::after{ transform:translate(0, 0); }

/* Up and to the right — for a link that leaves the page you are on rather
   than continuing it. Negative --sy because screen y grows downward. */
.shift-ne{ --sx:1.1em; --sy:-1.1em; --glyph:"↗"; }

/* Without the slide the two arrows would swap places instantly, which
   reads as a flicker rather than as motion. The resting arrow simply
   stays put and the second one is never brought on. */
@media (prefers-reduced-motion:reduce){
  .btn:hover .shift::before,
  .btn:focus-visible .shift::before{ transform:none; }
  .btn:hover .shift::after,
  .btn:focus-visible .shift::after{ transform:translate(calc(var(--sx) * -1), calc(var(--sy) * -1)); }
}

/* ---- Orbiting perimeter glow -------------------------------------------
   A hot spot travels around the button's edge while a blurred copy of the
   same gradient blooms outward. Three layers, and each is doing a job the
   others cannot:

     border-color   a dim, constant tint so the pill still reads as its own
                    colour at the darkest point in the orbit
     ::before       the travelling spot, masked down to the 1px ring
     ::after        the same gradient unmasked and blurred — the bloom

   Colour is a single custom property. The mechanic is written once and the
   caller sets --glow, the same way .shift takes a direction rather than
   carrying one copy of itself per direction.

   .glow goes on a WRAPPER around the button, not on the button. The glow
   has to stay at the edge, and the only way to keep the bloom out of the
   middle is to put something opaque on top of its inner half — which means
   the bloom and the button cannot be the same element. Masking the bloom
   into a ring instead does not work: CSS applies mask after filter, so the
   mask would cut the blurred output to a hard-edged band and take the soft
   falloff with it. Hence the opaque .btn face and the z-index ladder.

   The sweep is animated through an @property angle rather than by spinning
   a pseudo-element. A rotated element would have to be square and at least
   as wide as the pill's diagonal to keep its corners covered, which cannot
   be expressed without knowing the width; rotating the gradient's own
   `from` angle sidesteps the geometry entirely. Where @property is missing
   the angle simply never animates and the spot parks on one edge, which is
   the usual bargain: the decoration stops, the button does not. */
@property --glow-a{
  syntax: "<angle>";
  inherits: false;
  initial-value: 0deg;
}

.glow{
  /* Everything below goes through color-mix, and color-mix on an undefined
     --glow is invalid at computed-value time: the declaration drops and the
     effect vanishes rather than falling back. So there has to be a default
     — but it cannot be `--glow:var(--arc)` on this rule. A custom property
     set on the element beats one inherited from an ancestor, so that would
     silently overrule any hue a parent had set and paint every glow amber.
     Resolving it into a second name reads the inherited value first and
     only falls back when nobody upstream had an opinion. */
  --glow-c:var(--glow, var(--arc));
  position:relative;
  /* inline-flex so the wrapper hugs the button. Blocking it would stretch
     the pseudo-elements past the pill they are supposed to trace. Callers
     wanting a full-width button switch this to flex and set the button to
     width:100% — see .plan .go.glow. */
  display:inline-flex;
  max-width:100%;
  border-radius:999px;
  /* The standing halo, on the wrapper so it reads from the pill's edge. */
  box-shadow:0 0 20px -6px color-mix(in srgb, var(--glow-c) 55%, transparent);
}

/* The opaque face. This is the layer that keeps the effect on the edges:
   it sits above the bloom and clips it to whatever escapes past the pill.
   --void rather than transparent for exactly that reason, which does mean
   a glowing button stays void-dark on a card that lightens under the
   pointer — deliberate, it reads as recessed rather than as a mismatch. */
.glow > .btn{
  position:relative;
  z-index:2;
  width:100%;
  background:var(--void);
  border-color:color-mix(in srgb, var(--glow-c) 42%, transparent);
}

/* .btn:hover repaints border-color to --ash and background to a translucent
   wash. The first would drop a glowing button to grey the moment it was
   pointed at; the second would punch a hole in the occlusion and let the
   bloom back into the middle. Both have to be answered, opaquely. */
.glow > .btn:hover{
  background:color-mix(in srgb, var(--bone) 5%, var(--void));
  border-color:color-mix(in srgb, var(--glow-c) 72%, transparent);
}
.glow:hover{
  box-shadow:0 0 28px -5px color-mix(in srgb, var(--glow-c) 72%, transparent);
}

.glow::before,
.glow::after{
  content:"";
  position:absolute;
  inset:-1px;
  border-radius:inherit;
  pointer-events:none;
  /* 62deg of colour out of 360 puts the spot at roughly a sixth of the
     perimeter — long enough to read as a comet rather than a dot, short
     enough that the ring is clearly unlit behind it. */
  background:conic-gradient(from var(--glow-a),
    transparent 0deg,
    var(--glow-c) 26deg,
    color-mix(in srgb, var(--glow-c) 70%, transparent) 62deg,
    transparent 104deg,
    transparent 360deg);
  animation:glow-orbit var(--glow-dur, 3.4s) linear infinite;
  animation-delay:var(--glow-delay, 0s);
}

/* The ring. Two full-box masks composited so only the 1px padding band
   survives, which is the standard way to paint a gradient into a border
   that border-image cannot follow around a 999px radius. */
.glow::before{
  z-index:1;
  padding:1px;
  -webkit-mask:linear-gradient(#000 0 0) content-box,
               linear-gradient(#000 0 0);
          mask:linear-gradient(#000 0 0) content-box,
               linear-gradient(#000 0 0);
  -webkit-mask-composite:xor;
          mask-composite:exclude;
}

/* The bloom. z-index 0 rather than -1: a negative child would paint behind
   the wrapper but ALSO behind .plan's opaque background, which would hide
   it completely. The ladder is bloom 0, ring 1, button face 2 — so the
   button covers both in the middle and only the overhang past the pill
   survives. */
.glow::after{
  z-index:0;
  filter:blur(9px);
  opacity:.85;
}

@keyframes glow-orbit{ to{ --glow-a:360deg; } }

/* Reduced motion keeps the colour and drops the travel. The ring settles
   into an even tint rather than a spot parked at 0deg, which would leave
   one arbitrary edge permanently brighter.

   The bloom has to go rather than freeze. It is the one layer with no
   mask, so a flat colour behind it stops being a glow and becomes a fill
   — three solid pills that read as three primary CTAs, which is both the
   wrong emphasis and the wrong number of them. The standing box-shadow on
   .glow is already a halo and carries that job alone here. */
@media (prefers-reduced-motion:reduce){
  .glow::before{
    animation:none;
    background:color-mix(in srgb, var(--glow-c) 62%, transparent);
  }
  .glow::after{ display:none; }
}

/* .nav-burger{ display:none; } was here — a placeholder for a mobile menu
   toggle that was never built. No page has the element and no script adds
   it; the small-screen nav drops links with .hide-sm instead. */

/* ============================ FOOTER ============================ */
.foot{
  border-top:1px solid var(--edge);
  background:var(--graphite);
  padding:64px 0 34px;
  margin-top:auto;
  /* clips the oversized wordmark below. The mark is deliberately wider than
     the viewport, so this is what crops it at both gutters; it also contains
     the mark's parallax travel, which would otherwise hang past the bottom
     of the document and hand some browsers a stray scroll region. */
  position:relative;
  overflow:hidden;
}
/* the wordmark carries its own bottom margin and supplies the footer's
   bottom edge itself, so the padding that would otherwise sit under it has
   to go. Guarded rather than unconditional so a footer without the mark
   keeps its normal breathing room. */
.foot:has(.foot-mark){ padding-bottom:0; }
.foot-grid{
  display:grid;
  grid-template-columns:1.6fr repeat(3, 1fr);
  gap:44px 32px;
}
.foot-about p{
  color:var(--ash);
  font-size:14px;
  max-width:34ch;
  margin:18px 0 0;
}
.foot h4{
  font-family:var(--mono);
  font-size:10.5px; letter-spacing:.2em; text-transform:uppercase;
  color:var(--ash-dim);
  margin:0 0 16px; font-weight:400;
}
.foot ul{ list-style:none; margin:0; padding:0; display:grid; gap:11px; }
.foot ul a{ font-size:14px; color:var(--ash); transition:color .2s; }
.foot ul a:hover{ color:var(--arc); }

.foot-base{
  margin-top:52px; padding-top:26px;
  border-top:1px solid var(--edge);
  display:flex; flex-wrap:wrap; gap:14px 26px;
  align-items:center; justify-content:space-between;
  font-size:12.5px; color:var(--ash-dim);
  font-family:var(--mono);
}
/* The homepage no longer puts a nav in here — its two mailto addresses were
   removed — but the legal pages still do, for their cross-links. Keep. */
.foot-base nav{ display:flex; flex-wrap:wrap; gap:20px; }
.foot-base a:hover{ color:var(--ash); }

/* ---------- the oversized footer wordmark ----------
   Sized in vw rather than px so the bleed is the same proportion at every
   width: the line is deliberately wider than the viewport and gets cropped
   at both gutters, which is the whole point — the word is meant to read as
   too big for the screen. The crop is sideways only. The baseline stays
   fully visible with a sliver of room under it, so the letters sit ON the
   bottom edge rather than being sawn off by it.

   Size is a compromise the reference does not have to make: fourteen
   characters means matching its bleed ratio outright would eat three of
   them. This loses roughly one character's width across both gutters
   combined, which crops visibly without costing the word.

   The fill is a straight two-stop ramp that bottoms out at --graphite, the
   footer's own background, so the glyphs dissolve into the page edge
   instead of ending on a hard line. It is only a couple of steps off the
   background by design; this is texture, not content, and it must never
   compete with the links above it. */
.foot-mark{
  margin-top:68px;
  /* Archivo, deliberately, while the nav lockup above is Orbitron. This one
     was tried in the brand face and reverted: at 11.7vw the squared
     geometric letterforms read as a fence of identical uprights rather than
     as a word, and the mark stopped being texture and started competing
     with the links above it. The nav lockup is small enough that the same
     face reads as a logo instead. So --logo is not used here on purpose —
     do not "fix" the inconsistency by switching this back. */
  font-family:var(--display);
  font-variation-settings:"wdth" 100,"wght" 800;
  font-size:11.7vw;
  line-height:.74;
  /* .74 is not arbitrary: at Archivo's metrics it lands the line box top
     within a pixel of the cap line and its bottom 6px under the baseline,
     so the box IS the letterforms. That is what lets the gradient below
     clip cleanly to cap-top and baseline. The margin then buys back the
     sliver of room the letters sit on, about an eighth of the cap height,
     which is the reference's proportion. */
  margin-bottom:.05em;
  letter-spacing:-.02em;
  text-transform:uppercase;
  white-space:nowrap;
  user-select:none;
  -webkit-user-select:none;
  pointer-events:none;

  /* Centring an overflowing line, the hard way. `text-align:center` does not
     do it: once the line is wider than its block the browser keeps it flush
     to the start edge, so the whole bleed lands on the right and the word
     looks like it merely ran off the page. Sizing the box to the text and
     then pushing it half the CONTAINER's width right and half its OWN width
     back splits the overflow evenly, which is what makes the crop read as
     deliberate — half a letter lost at each gutter. */
  width:max-content;
  position:relative;
  left:50%;
  /* --fm-y is the parallax offset, written by js/footmark.js. It lives in a
     custom property rather than the script setting `transform` outright so
     that the centring translate above cannot be clobbered by it. */
  transform:translate3d(-50%, var(--fm-y, 0px), 0);
  /* clipped to the text box, which tight line-height has already pinned to
     cap-top and baseline — so the ramp runs the height of the letterforms
     and not a pixel more. Adding padding here would break that; the gap
     below is a margin for exactly that reason. */
  background:linear-gradient(180deg, #2C3438 0%, var(--graphite) 100%);
  -webkit-background-clip:text;
  background-clip:text;
  color:transparent;
}
@supports not ((-webkit-background-clip:text) or (background-clip:text)){
  .foot-mark{ color:#1C2226; background:none; }
}
/* Only set once js/footmark.js has taken over, so the resting state above
   is what ships if the script never runs. Scroll already makes the fade
   continuous, so the transition is not there to smooth ordinary scrolling —
   it is for the jumps: End, an anchor link, a restored scroll position.
   Those land the wordmark on a new opacity in one frame, and without this
   it pops. */
.foot-mark.is-live{
  transition:opacity .12s linear;
  /* Its own layer. The script rewrites transform and opacity every frame of
     the approach and this is a very wide run of 170px glyphs to re-raster.
     Scoped to .is-live so a reduced-motion or no-JS visitor, for whom the
     element never moves, does not pay for the layer. */
  will-change:transform, opacity;
}
@media (prefers-reduced-motion:reduce){
  .foot-mark{ --fm-y:0px !important; opacity:1 !important; }
}

/* ============================ LEGAL PAGES ============================ */
.legal-wrap{ padding:132px 0 96px; }
.legal-head{
  border-bottom:1px solid var(--edge);
  padding-bottom:34px; margin-bottom:44px;
}
.legal-head h1{
  font-family:var(--display);
  font-variation-settings:"wdth" 112,"wght" 780;
  font-size:clamp(32px,5.2vw,52px);
  line-height:1.04;
  letter-spacing:-.02em;
  margin:0 0 14px;
  text-transform:uppercase;
}
.legal-head .meta{
  font-family:var(--mono); font-size:12px; color:var(--ash-dim);
  letter-spacing:.06em;
}

.legal-body{
  display:grid;
  grid-template-columns:200px 1fr;
  gap:56px;
  align-items:start;
}
.legal-toc{ position:sticky; top:96px; }
.legal-toc h4{
  font-family:var(--mono); font-size:10.5px; letter-spacing:.2em;
  text-transform:uppercase; color:var(--ash-dim); margin:0 0 14px; font-weight:400;
}
.legal-toc ol{ list-style:none; margin:0; padding:0; display:grid; gap:9px; counter-reset:toc; }
.legal-toc a{
  font-size:13px; color:var(--ash); display:flex; gap:9px;
  transition:color .2s;
}
.legal-toc li{ counter-increment:toc; }
.legal-toc a::before{
  content:counter(toc,decimal-leading-zero);
  font-family:var(--mono); font-size:10.5px; color:var(--ash-dim); padding-top:2px;
}
.legal-toc a:hover{ color:var(--arc); }

.legal-prose{ max-width:70ch; }
.legal-prose section{ margin-bottom:44px; scroll-margin-top:96px; }
.legal-prose h2{
  font-family:var(--display);
  font-variation-settings:"wdth" 106,"wght" 700;
  font-size:19px; letter-spacing:.01em;
  margin:0 0 14px;
  display:flex; gap:12px; align-items:baseline;
}
.legal-prose h2 .n{
  font-family:var(--mono); font-size:11px; color:var(--arc); font-weight:400;
  letter-spacing:.08em;
}
.legal-prose h3{
  font-size:15px; font-weight:600; margin:24px 0 8px; color:var(--bone);
}
.legal-prose p, .legal-prose li{
  color:var(--ash); font-size:14.5px; line-height:1.72;
}
.legal-prose p{ margin:0 0 14px; }
.legal-prose ul{ margin:0 0 14px; padding-left:20px; display:grid; gap:8px; }
.legal-prose li::marker{ color:var(--arc-dim); }
.legal-prose strong{ color:var(--bone); font-weight:600; }
.legal-prose a{ color:var(--plasma); text-decoration:underline; text-underline-offset:3px; }

.legal-note{
  border:1px solid var(--edge);
  border-left:2px solid var(--arc);
  background:var(--graphite);
  padding:18px 20px;
  margin:0 0 32px;
}
.legal-note p{ margin:0; font-size:13.5px; }

/* ============================ CONTACT ============================
   The first form on the marketing site, so these are the site's first
   field styles and they are written to be reused rather than to fit one
   page. Nothing here is named .contact-*: the next form on the site
   should not have to choose between copying this block and importing a
   page's name.

   Dark-field inputs are the part people get wrong. A transparent field on
   a near-black background is invisible until it is focused, so the box has
   its own fill one step up from the page (--graphite on --void) and a
   border a step above that. Focus is --plasma, matching :focus-visible at
   the top of this file, because a form is exactly where a keyboard user
   needs to know where they are.
   ------------------------------------------------------------------ */
.form-wrap{ padding:132px 0 96px; }

.form-body{
  display:grid;
  grid-template-columns:1fr 1.15fr;
  gap:clamp(32px,6vw,80px);
  align-items:start;
}

/* The left rail. It is not decoration — it answers the two questions a
   reader has before typing: who reads this, and when do they answer. */
.form-aside{ position:sticky; top:110px; }
.form-aside h1{
  font-family:var(--display);
  font-variation-settings:"wdth" 112,"wght" 780;
  font-size:clamp(30px,4.4vw,46px);
  line-height:1.04; letter-spacing:-.02em;
  margin:0 0 16px; text-transform:uppercase;
}
.form-aside > p{ color:var(--ash); margin:0 0 28px; max-width:38ch; }
.form-facts{ list-style:none; margin:0 0 28px; padding:0; display:grid; gap:14px; }
.form-facts li{
  font-size:14px; color:var(--ash); line-height:1.5;
  padding-left:18px; position:relative;
}
.form-facts li::before{
  content:""; position:absolute; left:0; top:9px;
  width:6px; height:6px; background:var(--arc); border-radius:50%;
}
.form-facts b{ color:var(--bone); font-weight:600; }
.form-alt{
  border-top:1px solid var(--edge); padding-top:20px;
  font-size:13.5px; color:var(--ash-dim);
}
.form-alt a{ color:var(--plasma); text-decoration:underline; text-underline-offset:3px; }

/* The card. A border rather than a shadow: the page is already dark and a
   shadow on --void is a smudge. */
.form-card{
  border:1px solid var(--edge);
  background:var(--graphite);
  padding:clamp(22px,3.4vw,34px);
}

.field{ display:grid; gap:7px; margin-bottom:18px; }
.field-row{ display:grid; grid-template-columns:1fr 1fr; gap:18px; }
.field label{
  font-family:var(--mono); font-size:11px; letter-spacing:.08em;
  text-transform:uppercase; color:var(--ash);
}
/* Marked on the three fields the server actually requires, and on no
   others. Marking everything is the same as marking nothing, and the
   qualifying fields really are optional — an enquiry with a name, an email
   and a sentence is still a lead. */
.field label .req{ color:var(--arc); }
.field .hint{ font-size:12px; color:var(--ash-dim); }

.field input,
.field select,
.field textarea{
  font-family:var(--body); font-size:15px; color:var(--bone);
  background:var(--void);
  border:1px solid var(--edge);
  border-radius:3px;
  padding:11px 13px;
  width:100%;
  transition:border-color .18s, background .18s;
}
.field textarea{ resize:vertical; min-height:132px; line-height:1.55; }
.field input::placeholder,
.field textarea::placeholder{ color:var(--ash-dim); }
.field input:hover,
.field select:hover,
.field textarea:hover{ border-color:var(--ash-dim); }
.field input:focus,
.field select:focus,
.field textarea:focus{
  outline:none;                       /* replaced by the border + ring below */
  border-color:var(--plasma);
  box-shadow:0 0 0 3px rgba(74,219,238,.16);
}

/* The browser's own :invalid matches an empty required field from the
   moment the page loads, which would paint the form red before anyone has
   typed anything. .was-submitted is added by contact.js on the first failed
   submit, so the red only ever appears after the reader has been asked. */
.form-card.was-submitted .field input:invalid,
.form-card.was-submitted .field textarea:invalid{
  border-color:#E5484D;
}

.form-actions{
  display:flex; align-items:center; gap:16px; flex-wrap:wrap;
  margin-top:26px;
}
.form-actions .btn[disabled]{ opacity:.55; cursor:progress; }

/* One live region for both outcomes, so a screen reader is told the result
   whichever way it went, and so there is only one place that can be left
   holding a stale message. */
.form-msg{ font-size:13.5px; line-height:1.5; margin:0; }
.form-msg:empty{ display:none; }
.form-msg.is-error{ color:#F2777A; }
.form-msg.is-ok{ color:var(--plasma); }

/* The honeypot. Off-screen rather than display:none — a bot that skips
   hidden fields is a bot this would not have caught anyway, and the ones
   that fill everything are the ones worth catching. aria-hidden and
   tabindex=-1 in the markup keep it away from anybody real. */
.hp{
  position:absolute !important;
  left:-9999px; top:auto;
  width:1px; height:1px; overflow:hidden;
}

/* Replaces the card once the enquiry lands. A page that just greys the
   button out leaves the reader wondering whether to press it again. */
.form-done{
  border:1px solid var(--edge);
  border-left:2px solid var(--plasma);
  background:var(--graphite);
  padding:clamp(24px,3.4vw,36px);
}
.form-done h2{
  font-family:var(--display);
  font-variation-settings:"wdth" 112,"wght" 720;
  font-size:24px; margin:0 0 12px; text-transform:uppercase;
}
.form-done p{ color:var(--ash); margin:0 0 10px; }
.form-done p:last-child{ margin-bottom:0; }

/* ============================ RESPONSIVE ============================ */
@media (max-width:900px){
  .foot-grid{ grid-template-columns:1fr 1fr; gap:36px 24px; }
  .foot-about{ grid-column:1 / -1; }
  .legal-body{ grid-template-columns:1fr; gap:34px; }
  .legal-toc{ position:static; }
  .legal-toc ol{ grid-template-columns:repeat(auto-fit,minmax(150px,1fr)); }
  /* One column, and the rail stops sticking — pinned above a form it now
     sits directly on top of, it would follow the reader down the page and
     take a third of a short viewport with it. */
  .form-body{ grid-template-columns:1fr; gap:34px; }
  .form-aside{ position:static; }
}
@media (max-width:640px){
  .nav-links .hide-sm{ display:none; }
  .nav-links{ gap:16px; }
  .foot-grid{ grid-template-columns:1fr; }
  .foot-base{ flex-direction:column; align-items:flex-start; }
  /* Two 50% fields inside a phone gutter leave about 130px each, which is
     not enough for a company name to be readable while it is typed. */
  .field-row{ grid-template-columns:1fr; gap:0; }
  .form-wrap{ padding-top:112px; }
}

@media (prefers-reduced-motion:reduce){
  html{ scroll-behavior:auto; }
  *,*::before,*::after{
    animation-duration:.001ms !important;
    animation-iteration-count:1 !important;
    transition-duration:.001ms !important;
  }
}
