/* ============================================================
   Fashion Freelancing — NIGHT GLASS design system
   ------------------------------------------------------------
   The single source of truth for the dark, editorial glass look:
   tokens, atmosphere, nav/footer skin, type atoms, buttons,
   glass panels, reveal motion, section rhythm and form controls.

   Load order on every page:
     1. assets/styles.css   base reset + type scale (light tokens)
     2. assets/night.css    THIS FILE — re-skins everything to dark
     3. the page's own <style>  page-specific layout only

   Existing pages keep their inline <style> blocks; those come last
   and still win, so adopting this file cannot regress them. New
   pages (the specialist network) rely on this file plus
   assets/network.css and declare no tokens of their own.
   ============================================================ */

/* ------------------------------------------------------------
   Tokens, in three layers.

   1. :root                 — everything that does not change with
                              the theme (spacing, type, brand hues).
   2. :root                 — the LIGHT values. styles.css already
                              carries most of them; these are the ones
                              the night redesign introduced and light
                              never had.
   3. [data-theme="dark"]   — the dark values, which is what this file
                              used to apply unconditionally.

   The channel tokens (--surface-rgb, --ink-rgb, --shadow-rgb) exist so
   translucent overlays flip on their own. The night look is built from
   white at low alpha over a dark ground; light needs the same shapes in
   dark ink over a pale ground. Writing them as
   rgba(var(--surface-rgb), .14) means one token swap re-skins every
   hairline, glass fill and hover state instead of several hundred edits.
   ------------------------------------------------------------ */

:root {
  --u: 8px;
  --nav-h: 72px;
  --sans: 'Instrument Sans', 'Inter-fb', 'Inter-fb-r', system-ui, sans-serif;
  --disp: 'Plus Jakarta Sans', 'PJS-fb', 'PJS-fb-r', var(--sans);
  --mono: 'IBM Plex Mono', ui-monospace, monospace;
  --easing: cubic-bezier(.22, 1, .36, 1);

  /* Text on a saturated accent surface — hot-gradient buttons, ::selection.
     Those surfaces keep their colour in both themes, so their label stays
     white rather than following --ink. */
  --on-accent: #fff;

  /* the kicker hue where no service accent is in play */
  --brand-ink: #9A6203;

  /* the logo colours — service identity and accent rotation.
     Brand marks, so they hold steady across both themes. */
  --lg-orange: #F5A623;
  --lg-coral:  #F1543F;
  --lg-green:  #34C165;
  --lg-sky:    #4AA8F0;
  --lg-yellow: #EFD84A;
  --lg-violet: #A78BFA;
  --lg-teal:   #3EC8C0;
  --lg-pink:   #FF6FB3;
  --lg-lime:   #A8D84A;
  --lg-peri:   #7E9BEA;
}

/* ---------- LIGHT ----------
   styles.css supplies --paper*, --ink*, --line*, --champagne* and the
   shadows. What follows is only what night.css added on top. */
:root {
  --surface-rgb: 17, 20, 24;    /* overlays are dark ink over pale ground */
  /* The nav bar and drawers are a translucent sheet OVER the page, not a
     shadow. They have to follow the paper, or the bar stays dark above a
     light page and every link on it fails contrast. */
  --scrim-rgb:   255, 255, 255;

  /* Chip and label text. The pale originals were picked to sit on a dark
     ground; on the pale one they disappear, so light gets a saturated dark
     counterpart of the same hue. */
  --chip-violet: #653BFF;
  --chip-violet2: #693BFF;
  --chip-green: #147438;
  --chip-green2: #18733C;
  --chip-amber: #8D5A00;
  --chip-amber2: #706400;
  --chip-pink: #CB005B;
  --chip-blue: #0064C0;
  --ink-rgb:     17, 20, 24;
  --shadow-rgb:  20, 24, 30;

  /* A raised surface on a pale ground cannot be built by laying translucent
     black over it. That greys the paper, flattens the card into the page and
     is exactly why the light theme read as dirty next to the dark one, where
     the same trick works because white over a dark ground genuinely glows.
     Light has to lift the other way round: the card is white ON the warm
     ground, and its edge and a soft shadow do the separating.
     --surface-rgb itself stays dark ink — 105 borders and hairline rings
     across the site depend on that — so only the surfaces flip. */
  /* Every logo colour fails 4.5:1 on the pale ground — they run 1.4:1 to
     3.3:1 — so accent TEXT in light takes a darkened counterpart of the
     same hue, while decoration keeps the brand colour. These are the
     exact values each service page already uses for its own accent
     text, so a home card and the page it links to now agree. Dark
     needs no split: the bright hue already carries there. */
  --lg-orange-ink: #875400;
  --lg-coral-ink: #BD1701;
  --lg-green-ink: #166C34;
  --lg-sky-ink: #0261A9;
  --lg-yellow-ink: #6D5F02;
  --lg-violet-ink: #602AFF;
  --lg-teal-ink: #176A65;
  --lg-pink-ink: #BB0059;
  --lg-lime-ink: #4A680F;
  --lg-peri-ink: #164EE7;
  --lift-rgb: 255, 255, 255;   /* raised surfaces + bevels, both themes */
  /* --paper-2 was defined and then never used, so every section on a page
     shared one ground and the light theme read as a single flat sheet with
     white cards floating on it. Dark gets away with that because its cards
     glow; light has nothing to push against. Banding alternate sections
     gives the page its rhythm back and makes a white card sit ON something.
     Dark keeps one continuous ground, so its band is transparent. */
  --band: var(--paper-2);

  /* color-scheme tells the browser which way to paint the parts of a form
     control we cannot reach: the native <select> popup, the caret, spinners,
     scrollbars. Every page pinned it to `dark` in its own <style>, so on the
     light theme Chrome kept drawing those internals dark against white
     fields. It has to track the theme instead. `:root` outranks the pages'
     `html` rule, so this wins without editing each one. */
  color-scheme: light;
  /* the native dropdown list: its ground is painted by the browser, so it
     needs a real colour rather than a translucent surface token */
  --option-bg: #FFFFFF;
  /* Surfaces whose alpha has to differ by theme: on the dark ground a 6%
     white wash is a visible lift, but on a pale ground the same wash is
     invisible, so light needs near-opaque white and dark must keep its
     originals exactly. */
  --lit-1:       rgba(255, 255, 255, .92);   /* spotlit card, top stop    */
  --lit-2:       rgba(255, 255, 255, .82);   /* spotlit card, bottom stop */
  --bevel:       rgba(255, 255, 255, .60);   /* top inner highlight       */
  --field:       rgba(255, 255, 255, .90);   /* form field well           */
  --field-focus: #FFFFFF;
  --glass:        rgba(255, 255, 255, .74);
  --glass-hover:  #FFFFFF;
  --glass-border: rgba(var(--surface-rgb), .10);
  /* the shadow is what a light card lifts with; dark needs none */
  --glass-shadow:   0 1px 2px rgba(20, 24, 30, .04), 0 10px 24px -14px rgba(20, 24, 30, .18);
  --glass-shadow-h: 0 2px 4px rgba(20, 24, 30, .05), 0 16px 34px -16px rgba(20, 24, 30, .24);

  --grad-hot: linear-gradient(90deg, #5468F5, #C8385C);

  /* status tints — approval states, availability, validation.
     Darkened from the night set so they carry on a pale ground. */
  --ok:   #1E7A47;
  --warn: #9A6410;
  --bad:  #C8385C;
}

/* ---------- DARK ----------
   Applied when the visitor has chosen dark, and by default when their
   system asks for it and they have not chosen light. */
:root[data-theme="dark"] {
  --brand-ink: var(--lg-orange);
  --paper:   #0C0A1C;
  --paper-2: #131024;
  --paper-3: rgba(var(--surface-rgb), .055);
  --ink:     #F4F2FA;
  /* The ramp must be complete. --ink-2, --ink-6 and --ink-8 were absent, so
     anything using them fell through to the light theme's near-black. */
  --ink-2:   rgba(var(--ink-rgb), .92);
  --ink-3:   rgba(var(--ink-rgb), .84);
  --ink-4:   rgba(var(--ink-rgb), .62);
  --ink-5:   rgba(var(--ink-rgb), .56);
  --ink-6:   rgba(var(--ink-rgb), .34);
  --ink-7:   rgba(var(--ink-rgb), .20);
  --ink-8:   rgba(var(--ink-rgb), .12);
  --line:    rgba(var(--surface-rgb), .10);
  --line-2:  rgba(var(--surface-rgb), .16);
  --champagne: #8B5CF6; --champagne-2: #A78BFA; --champagne-50: rgba(139,92,246,.22);

  --lg-orange-ink: #F5A623;
  --lg-coral-ink: #F1543F;
  --lg-green-ink: #34C165;
  --lg-sky-ink: #4AA8F0;
  --lg-yellow-ink: #EFD84A;
  --lg-violet-ink: #A78BFA;
  --lg-teal-ink: #3EC8C0;
  --lg-pink-ink: #FF6FB3;
  --lg-lime-ink: #A8D84A;
  --lg-peri-ink: #7E9BEA;
  color-scheme: dark;
  --option-bg: #131024;
  --band: transparent;
  --surface-rgb: 255, 255, 255;   /* overlays are white over dark ground */
  --lift-rgb: 255, 255, 255;
  --lit-1:       rgba(255, 255, 255, .09);
  --lit-2:       rgba(255, 255, 255, .06);
  --bevel:       rgba(255, 255, 255, .18);
  --field:       rgba(255, 255, 255, .06);
  --field-focus: rgba(255, 255, 255, .08);
  --scrim-rgb:   16, 13, 32;
  --chip-violet: #E9E3FF;
  --chip-violet2: #DED4FF;
  --chip-green: #8BE3AC;
  --chip-green2: #C4EFD5;
  --chip-amber: #F7CE86;
  --chip-amber2: #F6E97E;
  --chip-pink: #FFD0E5;
  --chip-blue: #CFE8FF;
  --ink-rgb:     244, 242, 250;
  --shadow-rgb:  0, 0, 0;

  --glass:        rgba(var(--surface-rgb), .055);
  --glass-hover:  rgba(var(--surface-rgb), .095);
  --glass-border: rgba(var(--surface-rgb), .14);
  --glass-shadow:   none;
  --glass-shadow-h: none;
  --grad-hot: linear-gradient(90deg, #8B5CF6, #FF4FA0);

  --ok:   #34C165;
  --warn: #F5A623;
  --bad:  #FF4FA0;

  --shadow-1: 0 1px 2px rgba(var(--shadow-rgb), .5), 0 1px 1px rgba(var(--shadow-rgb), .4);
  --shadow-2: 0 16px 38px -16px rgba(var(--shadow-rgb), .7);
  --shadow-3: 0 34px 70px -24px rgba(var(--shadow-rgb), .8);
}

/* System preference, for visitors who have not picked a side. */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --brand-ink: var(--lg-orange);
    --paper:   #0C0A1C;
    --paper-2: #131024;
    --paper-3: rgba(var(--surface-rgb), .055);
    --ink:     #F4F2FA;
    --ink-2:   rgba(var(--ink-rgb), .92);
    --ink-3:   rgba(var(--ink-rgb), .84);
    --ink-4:   rgba(var(--ink-rgb), .62);
    --ink-5:   rgba(var(--ink-rgb), .56);
    --ink-6:   rgba(var(--ink-rgb), .34);
    --ink-7:   rgba(var(--ink-rgb), .20);
    --ink-8:   rgba(var(--ink-rgb), .12);
    --line:    rgba(var(--surface-rgb), .10);
    --line-2:  rgba(var(--surface-rgb), .16);
    --champagne: #8B5CF6; --champagne-2: #A78BFA; --champagne-50: rgba(139,92,246,.22);
  
    --lg-orange-ink: #F5A623;
    --lg-coral-ink: #F1543F;
    --lg-green-ink: #34C165;
    --lg-sky-ink: #4AA8F0;
    --lg-yellow-ink: #EFD84A;
    --lg-violet-ink: #A78BFA;
    --lg-teal-ink: #3EC8C0;
    --lg-pink-ink: #FF6FB3;
    --lg-lime-ink: #A8D84A;
    --lg-peri-ink: #7E9BEA;
    color-scheme: dark;
    --option-bg: #131024;
    --band: transparent;
    --surface-rgb: 255, 255, 255;   /* overlays are white over dark ground */
    --lift-rgb:    255, 255, 255;
    --lit-1:       rgba(255, 255, 255, .09);
    --lit-2:       rgba(255, 255, 255, .06);
    --bevel:       rgba(255, 255, 255, .18);
    --field:       rgba(255, 255, 255, .06);
    --field-focus: rgba(255, 255, 255, .08);
    --scrim-rgb:   16, 13, 32;
    --chip-violet: #E9E3FF;
    --chip-violet2: #DED4FF;
    --chip-green: #8BE3AC;
    --chip-green2: #C4EFD5;
    --chip-amber: #F7CE86;
    --chip-amber2: #F6E97E;
    --chip-pink: #FFD0E5;
    --chip-blue: #CFE8FF;
    --ink-rgb:     244, 242, 250;
    --shadow-rgb:  0, 0, 0;
  
    --glass:        rgba(var(--surface-rgb), .055);
    --glass-hover:  rgba(var(--surface-rgb), .095);
    --glass-border: rgba(var(--surface-rgb), .14);
    --glass-shadow:   none;
    --glass-shadow-h: none;
    --grad-hot: linear-gradient(90deg, #8B5CF6, #FF4FA0);
  
    --ok:   #34C165;
    --warn: #F5A623;
    --bad:  #FF4FA0;
  
    --shadow-1: 0 1px 2px rgba(var(--shadow-rgb), .5), 0 1px 1px rgba(var(--shadow-rgb), .4);
    --shadow-2: 0 16px 38px -16px rgba(var(--shadow-rgb), .7);
    --shadow-3: 0 34px 70px -24px rgba(var(--shadow-rgb), .8);
  }
}

/* metric-matched fallbacks — the webfont swap no longer moves layout (CLS) */
@font-face { font-family: 'Inter-fb'; src: local('Arial'); size-adjust: 104%; ascent-override: 92%; descent-override: 23%; line-gap-override: 0%; }
@font-face { font-family: 'PJS-fb'; src: local('Arial'); size-adjust: 105%; ascent-override: 96%; descent-override: 24%; line-gap-override: 0%; }

html { color-scheme: light dark; scroll-behavior: smooth; }
@media (prefers-reduced-motion: reduce) { html { scroll-behavior: auto; } }

body {
  background: var(--paper);
  color: var(--ink);
  font-family: var(--sans);
  font-size: 16px; line-height: 1.55;
  -webkit-font-smoothing: antialiased;
  overflow-x: clip;
}
/* styles.css paints a light gradient wash behind every page — the night
   system supplies its own atmosphere via .scene, so switch that one off. */
body::before, body::after { content: none; }
::selection { background: #8B5CF6; color: var(--on-accent); }

.wrap { width: 100%; max-width: 1240px; margin: 0 auto; padding: 0 28px; }
@media (max-width: 720px) { .wrap { padding: 0 20px; } }

/* reserve the injected nav's space — kills the layout shift (CLS) */
#site-nav { min-height: 92px; }
@media (max-width: 720px) { #site-nav { min-height: 90px; } }

.skip-link {
  position: fixed; top: -100px; left: 20px; z-index: 10001;
  background: var(--ink); color: var(--paper); padding: 14px 22px;
  font-family: var(--mono); font-size: 11px; letter-spacing: .14em; text-transform: uppercase;
  border-radius: 999px; transition: top .2s ease;
}
.skip-link:focus { top: 16px; }

/* ============================================================
   Atmosphere — drifting blobs, grain, cursor glow
   Markup (once per page, right after <body>):
     <div class="scene" aria-hidden="true">
       <div class="blob b1"></div> … <div class="blob b5"></div>
     </div>
     <div class="grain" aria-hidden="true"></div>
     <div class="glow" id="glow" aria-hidden="true"></div>
   ============================================================ */
.scene { position: fixed; inset: 0; z-index: 0; overflow: hidden; pointer-events: none; }
.blob { position: absolute; border-radius: 50%; filter: blur(110px); will-change: transform; transform: translateZ(0); backface-visibility: hidden; }
/* One temperature, not five.
   These were five blobs in five hues — violet, coral, green, sky, orange —
   drifting behind every page at once. Five competing hues in the background
   is what stops an accent meaning anything in the foreground: by the time a
   button is violet, violet has already appeared four times behind it.
   Now a single cool wash gives the ground its depth and leaves the accent
   free to mark the one thing that matters on the page. */
.b1 { width: 620px; height: 620px; background: #6D5BD0; top: -190px; left: -140px; opacity: .30; animation: drift-a 32s ease-in-out infinite; }
.b2 { width: 520px; height: 520px; background: #4A3F94; top: 34%; right: -190px; opacity: .24; animation: drift-b 38s ease-in-out infinite; }
.b3 { width: 460px; height: 460px; background: #2E2A5E; bottom: -180px; left: 18%; opacity: .26; animation: drift-c 35s ease-in-out infinite; }
.b4, .b5 { display: none; }
@keyframes drift-a { 0%,100% { transform: translate3d(0,0,0) scale(1); } 50% { transform: translate3d(60px,40px,0) scale(1.12); } }
@keyframes drift-b { 0%,100% { transform: translate3d(0,0,0) scale(1); } 50% { transform: translate3d(-70px,50px,0) scale(.9); } }
@keyframes drift-c { 0%,100% { transform: translate3d(0,0,0) scale(1); } 50% { transform: translate3d(40px,-60px,0) scale(1.08); } }

.grain {
  position: fixed; inset: 0; z-index: 1; pointer-events: none; opacity: .04;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='120' height='120'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
}
.glow {
  position: fixed; width: 440px; height: 440px; border-radius: 50%; pointer-events: none; z-index: 2;
  background: radial-gradient(circle, rgba(139,92,246,.14), transparent 70%);
  transform: translate(-50%,-50%); left: -600px; top: -600px;
  transition: left .12s linear, top .12s linear;
}
@media (prefers-reduced-motion: reduce) { .blob { animation: none; } .glow { display: none; } }
main { position: relative; z-index: 3; }

/* ------------------------------------------------------------
   Light theme is flat.

   The drifting blobs, the grain and the cursor glow are what make the
   dark theme feel like night glass. On white they read as smudges — a
   product site in daylight is a plain ground, and the content carries
   the page instead. The elements stay in the markup and simply stop
   painting, so nothing has to change per page.
   ------------------------------------------------------------ */
:root:not([data-theme="dark"]) .scene,
:root:not([data-theme="dark"]) .grain,
:root:not([data-theme="dark"]) .glow { display: none; }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .scene,
  :root:not([data-theme="light"]) .grain,
  :root:not([data-theme="light"]) .glow { display: block; }
}

/* ============================================================
   Injected nav + footer (assets/site.js) — night skin
   ============================================================ */
.topnav {
  position: sticky; top: 12px !important;
  width: min(1180px, calc(100% - 28px));
  margin: 12px auto 0;
  border-radius: 999px;
  background: rgba(var(--scrim-rgb), .62) !important;
  backdrop-filter: saturate(160%) blur(20px) !important;
  -webkit-backdrop-filter: saturate(160%) blur(20px) !important;
  border: 1px solid rgba(var(--surface-rgb), .12) !important;
  border-bottom: 1px solid rgba(var(--surface-rgb), .12) !important;
  box-shadow: 0 12px 44px -12px rgba(var(--shadow-rgb), .55) !important;
  overflow: hidden;
}
.topnav .container, .topnav .topnav-inner { padding-left: 20px; padding-right: 12px; }
.topnav.is-scrolled { border-radius: 999px; }
.topnav-mobile { top: 88px !important; border-radius: 22px; left: 12px !important; right: 12px !important; border: 1px solid rgba(var(--surface-rgb), .12); }
.topnav-links a { color: rgba(var(--ink-rgb), .82) !important; }
:root[data-theme="dark"] .topnav-links a { color: rgba(var(--ink-rgb), .66) !important; }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .topnav-links a { color: rgba(var(--ink-rgb), .66) !important; }
}
.topnav-links a:hover, .topnav-links a.active { color: var(--ink) !important; }
.topnav-burger span { background: var(--ink) !important; }
/* Transparent logo artwork. On the dark ground a violet/pink light traces
   its shape so the dark strokes stay readable; on white there is nothing to
   rescue and the same glow reads as a smudge behind the mark, so light drops
   it entirely. */
.topnav .logo-img, .footer .logo-img {
  background: transparent;
  filter: drop-shadow(0 4px 16px rgba(139,92,246,.55)) drop-shadow(0 0 28px rgba(255,79,160,.32));
  transition: filter .35s ease;
}
.topnav .logo:hover .logo-img, .footer .logo:hover .logo-img {
  filter: drop-shadow(0 4px 20px rgba(139,92,246,.75)) drop-shadow(0 0 38px rgba(255,79,160,.5));
}
:root:not([data-theme="dark"]) .topnav .logo-img,
:root:not([data-theme="dark"]) .footer .logo-img,
:root:not([data-theme="dark"]) .topnav .logo:hover .logo-img,
:root:not([data-theme="dark"]) .footer .logo:hover .logo-img { filter: none; }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .topnav .logo-img,
  :root:not([data-theme="light"]) .footer .logo-img {
    filter: drop-shadow(0 4px 16px rgba(139,92,246,.55)) drop-shadow(0 0 28px rgba(255,79,160,.32));
  }
}
.topnav .btn-primary, .topnav-mobile .btn-primary {
  background: var(--grad-hot) !important; color: var(--on-accent) !important;
  border-radius: 999px !important; border: 0 !important;
  box-shadow: 0 8px 26px rgba(139,92,246,.4) !important;
}
.topnav-mobile { background: rgba(var(--scrim-rgb), .92) !important; bottom: 12px !important; border: 1px solid rgba(var(--surface-rgb), .14) !important; box-shadow: 0 24px 70px -24px rgba(var(--shadow-rgb), .75); }
.topnav-mobile-inner { padding: 30px 24px calc(24px + env(safe-area-inset-bottom)) !important; }
.topnav-mobile-links { flex: 0 0 auto !important; justify-content: flex-start !important; padding: 8px 0 0 !important; }
.topnav-mobile-cta { margin-top: auto !important; }
.topnav-mobile-links a {
  display: block; width: 100%; text-align: left !important;
  color: rgba(var(--ink-rgb), .8) !important;
  font-family: var(--disp) !important; font-size: 24px !important; font-weight: 700 !important;
  letter-spacing: -.02em; padding: 18px 4px !important;
  border-bottom: 1px solid rgba(var(--surface-rgb), .08);
}
.topnav-mobile-links a:last-child { border-bottom: 0; }
.topnav-burger { background: rgba(var(--surface-rgb), .07) !important; border: 1px solid rgba(var(--surface-rgb), .16) !important; }
.topnav-burger.is-open span { background: var(--ink) !important; }
.footer { background: rgba(var(--surface-rgb), .03) !important; border-top: 1px solid var(--line) !important; }
#site-footer * { background-color: transparent; }

/* ============================================================
   Type atoms
   ============================================================ */
/* ------------------------------------------------------------
   Section grammar
   ------------------------------------------------------------
   One structure, used by every section on every page:

       eyebrow    12px, uppercase, barely tracked
       headline   clamp to ~44px, leading 1.12, weight 600
       subcopy    17px, capped at 68 characters

   The point is the repetition. Once a reader has understood one
   section they know how to read all of them, and stop parsing the
   layout to get at the content. Values drifted per page before —
   weight 800 against 600, leading 1.02 against 1.14, eyebrows tracked
   anywhere from .1em to .2em — and the page read as a set of unrelated
   blocks rather than one argument.
   ------------------------------------------------------------ */
.kicker {
  font-family: var(--mono); font-size: 12px; font-weight: 500;
  /* .2em on an already-uppercase label makes the eye read letters
     rather than words. Just enough to separate the caps. */
  letter-spacing: .04em; text-transform: uppercase; color: var(--ink-5);
}
.h-display {
  /* 600, not 800: at display size the heavier weight reads as shouting
     where the lighter one reads as assured. 1.12 leading so a headline
     that wraps to three lines still breathes. */
  font-family: var(--disp); font-weight: 600; letter-spacing: -.025em; line-height: 1.12;
  color: var(--ink);
}
.grad { background: var(--grad-hot); -webkit-background-clip: text; background-clip: text; color: transparent; }
.sub { color: var(--ink-4); }

/* ============================================================
   Surfaces + buttons
   ============================================================ */
.glass-p {
  background: var(--glass);
  border: 1px solid var(--glass-border);
  box-shadow: var(--glass-shadow, none);
  backdrop-filter: blur(18px); -webkit-backdrop-filter: blur(18px);
  border-radius: 20px;
}
.btn-hot {
  display: inline-flex; align-items: center; justify-content: center; gap: 10px;
  padding: 15px 30px; min-height: 50px; border: 0; cursor: pointer;
  border-radius: 999px; background: var(--grad-hot); color: var(--on-accent);
  font-family: var(--sans); font-size: 14px; font-weight: 600; text-decoration: none;
  box-shadow: 0 8px 30px rgba(139,92,246,.35);
  transition: transform .25s var(--easing), box-shadow .25s var(--easing);
}
.btn-hot:hover { transform: translateY(-2px); box-shadow: 0 12px 40px rgba(255,79,160,.4); }
.btn-hot[disabled], .btn-glass[disabled] { opacity: .5; cursor: not-allowed; transform: none; }
.btn-glass {
  display: inline-flex; align-items: center; justify-content: center; gap: 10px;
  padding: 15px 28px; min-height: 50px; cursor: pointer;
  border-radius: 999px; background: var(--glass); color: var(--ink);
  border: 1px solid var(--glass-border);
  backdrop-filter: blur(12px); -webkit-backdrop-filter: blur(12px);
  font-family: var(--sans); font-size: 14px; font-weight: 500; text-decoration: none;
  transition: background .25s ease, transform .25s var(--easing);
}
.btn-glass:hover { background: var(--glass-hover); transform: translateY(-2px); }
/* compact variant for card actions and filter rows */
.btn-hot.btn-sm, .btn-glass.btn-sm { padding: 10px 18px; min-height: 44px; font-size: 13px; }
a:focus-visible, button:focus-visible, input:focus-visible,
select:focus-visible, textarea:focus-visible, summary:focus-visible,
[tabindex]:focus-visible { outline: 2px solid #A78BFA; outline-offset: 3px; }

/* ============================================================
   Reveal-on-scroll — assets/site.js adds .in when the element enters
   ============================================================ */
/* Reveal-on-scroll. The hidden state is scoped to .rv-on, which the inline
   head script sets only when script is running and IntersectionObserver
   exists — so if anything goes wrong the content is simply visible rather
   than invisible forever. */
.rv { transition: opacity .7s var(--easing), transform .7s var(--easing); }
.rv-on .rv { opacity: 0; transform: translateY(24px); }

/* ------------------------------------------------------------
   Entrances vary by what is entering.
   ------------------------------------------------------------
   One fade-up applied to every element on the page is the most
   recognisable machine-made motion there is: thirty things doing the
   same thing at the same distance. What a thing is should decide how it
   arrives — media is revealed, display type is set, figures count up
   into place, list rows drift in from the side.

   Each still resolves to the same resting state, so nothing depends on
   the animation having run.
   ------------------------------------------------------------ */

/* media: uncovered rather than moved */
.rv-on .rv-media { opacity: 0; transform: none; clip-path: inset(0 0 100% 0); transition: clip-path .9s cubic-bezier(.16,1,.3,1), opacity .5s ease; }
.rv-on .rv-media.in { opacity: 1; clip-path: inset(0 0 0 0); }

/* display type: set into place from slightly heavier and lower */
.rv-on .rv-display { opacity: 0; transform: translateY(14px) scale(.985); transition: opacity .6s ease, transform .7s cubic-bezier(.16,1,.3,1); }
.rv-on .rv-display.in { opacity: 1; transform: none; }

/* figures: rise into their slot, quick in and slow to settle */
.rv-on .rv-figure { opacity: 0; transform: translateY(18px); transition: opacity .25s ease, transform .8s cubic-bezier(.33,1,.68,1); }
.rv-on .rv-figure.in { opacity: 1; transform: none; }

/* index rows: drift in from the side, so a list reads as a list arriving */
.rv-on .rv-row { opacity: 0; transform: translateX(-16px); transition: opacity .5s ease, transform .6s cubic-bezier(.16,1,.3,1); }
.rv-on .rv-row.in { opacity: 1; transform: none; }

/* A reduced variant, not a disabled one: everything is simply already here. */
@media (prefers-reduced-motion: reduce) {
  .rv-on .rv, .rv-on .rv-media, .rv-on .rv-display, .rv-on .rv-figure, .rv-on .rv-row {
    opacity: 1; transform: none; clip-path: none; transition: none;
  }
}
.rv-on .rv.in { opacity: 1; transform: none; }
.rv-d1 { transition-delay: .08s; } .rv-d2 { transition-delay: .16s; } .rv-d3 { transition-delay: .24s; }
@media (prefers-reduced-motion: reduce) { .rv { opacity: 1; transform: none; transition: none; } }

/* ============================================================
   Section rhythm
   ============================================================ */
.sec { position: relative; padding: calc(var(--u) * 13) 0; }
@media (max-width: 720px) { .sec { padding: calc(var(--u) * 8) 0; } }
.sec-head { max-width: 660px; margin: 0 auto 40px; text-align: center; }
.sec-head h2 { font-size: clamp(28px, 3.4vw, 44px); margin-top: 12px; }
/* The bridge between the claim and the content under it. Sections that
   jump straight from a headline into a grid leave the reader holding a
   claim with nothing connecting it to what follows. */
.sec-head .sub { color: var(--ink-4); font-size: 17px; margin-top: 14px; line-height: 1.6; }
/* Beyond ~70 characters the eye loses its place coming back to the next
   line. Applies wherever prose sits, not only in a section head. */
.sec-head .sub, .hero .sub { max-width: 68ch; margin-left: auto; margin-right: auto; }

/* ============================================================
   Forms — .cform wraps labelled .fl + .fi controls
   ============================================================ */
.cform { display: grid; gap: 15px; }
.cform .row2 { display: grid; grid-template-columns: 1fr 1fr; gap: 14px; }
/* A label wrapping a field is a block. A label that IS the control — a choice
   chip or a picker card — brings its own layout, so it must not be clobbered
   here; without the exclusion those controls lose `display:flex` and their box
   and text stop lining up. */
.cform label:not(.opt):not(.pick) { display: block; }
.cform .fl { font-size: 13px; font-weight: 500; color: var(--ink-3); letter-spacing: -.005em; display: block; margin-bottom: 7px; }
.cform .fl .rq { color: #FF4FA0; margin-left: 3px; }
.cform .fi {
  width: 100%;
  /* A field is a place to put something into, so it reads as inset from the
     page rather than laid on top of it. On the dark ground a pale wash does
     that. On white the same idea inverted became a grey smudge sitting on an
     already-grey panel, with almost nothing separating the two — so light
     gives the field the paper colour and lets a real border define its edge. */
  background: var(--paper-3);
  border: 1px solid var(--line-2); border-radius: 13px;
  padding: 13px 15px;
  /* 16px is the floor: iOS auto-zooms the page on focus below it. */
  font-family: var(--sans); font-size: 16px; color: var(--ink);
  transition: border-color .25s ease, box-shadow .25s ease, background .25s ease;
}
.cform .fi::placeholder { color: var(--ink-5); }
.cform .fi:hover { border-color: rgba(var(--surface-rgb), .32); }
.cform .fi:focus {
  /* Focus is said by the border and the ring. It used to also darken the
     background, which on white turned the field you were typing in grey —
     the one field on the page that should be clearest. */
  outline: none; border-color: var(--champagne);
  box-shadow: 0 0 0 3px var(--champagne-50);
}
.cform select.fi { -webkit-appearance: none; appearance: none; cursor: pointer;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23A78BFA' stroke-width='2.4' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M6 9l6 6 6-6'/%3E%3C/svg%3E");
  background-repeat: no-repeat; background-position: right 14px center; background-size: 14px;
  padding-right: 40px;
}
.cform select.fi option { background: var(--option-bg); color: var(--ink); }
.cform textarea.fi { min-height: 110px; resize: vertical; }

/* File inputs default to an OS-styled button that ignores the design system.
   Style the button part so an upload row reads like the fields around it. */
.cform input[type='file'].fi { padding: 9px 12px; cursor: pointer; line-height: 1.6; }
.cform input[type='file'].fi::file-selector-button {
  margin-right: 12px; padding: 8px 15px;
  border: 1px solid var(--glass-border); border-radius: 999px;
  background: rgba(var(--surface-rgb), .08); color: var(--ink);
  font-family: var(--sans); font-size: 13px; font-weight: 500; cursor: pointer;
  transition: background .2s ease, border-color .2s ease;
}
.cform input[type='file'].fi::file-selector-button:hover {
  background: var(--glass-hover); border-color: rgba(var(--surface-rgb), .3);
}
.cform .fi[aria-invalid="true"] { border-color: #FF4FA0; background: rgba(255,79,160,.08); }
.cform .fh { display: block; margin-top: 6px; font-size: 12.5px; color: var(--ink-5); line-height: 1.5; }

/* A link that stands on its own is a control, not prose, so it gets a real
   touch target. Links inside a sentence keep their natural size. */
.link-t {
  display: inline-flex; align-items: center; min-height: 44px;
  color: var(--champagne-2); font-size: 13.5px;
}
.link-t:hover { color: var(--ink); }
.cform-err {
  display: block; margin: 6px 0 0; font-size: 13px; line-height: 1.45; color: #FF7AB8;
}
/* A field that failed reads as failed at a glance, not only by its message. */
.cform .fi[aria-invalid='true'] { border-color: #FF4FA0; background: rgba(255,79,160,.08); }
.opt:has(input[aria-invalid='true']) { border-color: #FF4FA0; }

/* Password reveal — the field keeps its full width, the control sits inside. */
.pw-wrap { position: relative; display: block; }
.pw-wrap .fi { padding-right: 86px; padding-top: 15px; padding-bottom: 15px; }
.pw-toggle {
  position: absolute; right: 5px; top: 50%; transform: translateY(-50%);
  /* 44px is the touch minimum, and it still clears the field's own height. */
  min-height: 44px; min-width: 44px; padding: 0 16px; border-radius: 999px;
  background: rgba(var(--surface-rgb), .08); border: 1px solid var(--glass-border);
  color: var(--ink-3); font-family: var(--sans); font-size: 12px; font-weight: 500;
  cursor: pointer; transition: background .2s ease, color .2s ease;
}
.pw-toggle:hover { background: var(--glass-hover); color: var(--ink); }

/* A submitting button is visibly busy and cannot be pressed again. */
button[aria-busy='true'] { opacity: .7; cursor: progress; }
@media (max-width: 820px) { .cform .row2 { grid-template-columns: 1fr; } }

/* success state shared by the contact form and every network flow */
.sent-ok { text-align: center; padding: 40px 20px; }
.sent-ok .ok {
  width: 54px; height: 54px; margin: 0 auto; border-radius: 50%;
  background: var(--grad-hot); color: var(--on-accent); font-size: 24px; line-height: 54px;
  box-shadow: 0 14px 30px rgba(139,92,246,.45);
}
.sent-ok h3 { font-family: var(--disp); font-size: 26px; font-weight: 700; margin: 16px 0 8px; }
.sent-ok p { color: var(--ink-4); font-size: 14.5px; margin: 0; }

/* ============================================================
   Mobile: lighter effect cost, same visuals
   ============================================================ */
@media (max-width: 720px) {
  .blob { filter: blur(60px); }
  .b4, .b5 { display: none; }
  .glass-p { -webkit-backdrop-filter: blur(9px); backdrop-filter: blur(9px); }
  .topnav { -webkit-backdrop-filter: saturate(160%) blur(12px) !important; backdrop-filter: saturate(160%) blur(12px) !important; }
  .rv { transition-duration: .45s; }
}

/* ------------------------------------------------------------
   Theme toggle
   ------------------------------------------------------------
   One control, shown in the desktop nav and again in the mobile
   drawer. It states the destination rather than the current state
   ("Switch to light theme"), because a control labelled with where
   you already are is ambiguous. The icon shows the destination too:
   a sun while you are in the dark, a moon while you are in the light.
   ------------------------------------------------------------ */
.theme-toggle {
  display: inline-flex; align-items: center; justify-content: center;
  width: 40px; height: 40px; flex: 0 0 auto;
  border-radius: 999px; cursor: pointer;
  background: var(--glass);
  border: 1px solid var(--glass-border);
  color: var(--ink-3);
  transition: background .2s var(--easing), color .2s var(--easing), border-color .2s var(--easing);
}
.theme-toggle:hover { background: var(--glass-hover); color: var(--ink); }
.theme-toggle:focus-visible { outline: 2px solid var(--champagne); outline-offset: 2px; }

.theme-toggle svg {
  width: 19px; height: 19px; display: block;
  fill: none; stroke: currentColor; stroke-width: 1.8;
  stroke-linecap: round; stroke-linejoin: round;
}
/* Show the destination: sun to go light, moon to go dark. */
.theme-toggle .t-sun  { display: none; }
.theme-toggle .t-moon { display: block; }
:root[data-theme="dark"] .theme-toggle .t-sun  { display: block; }
:root[data-theme="dark"] .theme-toggle .t-moon { display: none; }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .theme-toggle .t-sun  { display: block; }
  :root:not([data-theme="light"]) .theme-toggle .t-moon { display: none; }
}

/* In the mobile drawer it sits above the CTA and takes the full width,
   so it is a comfortable target rather than a 40px dot in a corner. */
.theme-toggle-wide {
  width: 100%; height: 46px; border-radius: 12px; gap: 10px;
  margin-bottom: 10px; font: 500 15px/1 var(--sans);
}
.theme-toggle-wide::after {
  content: 'Dark theme'; color: inherit;
}
:root[data-theme="dark"] .theme-toggle-wide::after { content: 'Light theme'; }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .theme-toggle-wide::after { content: 'Light theme'; }
}

/* ------------------------------------------------------------
   Compact heroes
   ------------------------------------------------------------
   Every service page opened with a hero pinned to the full viewport
   (min-height: calc(100vh - 104px)) — a whole screen before the visitor
   learns anything, in either theme. The hero now sizes to its content,
   with a floor on desktop so a short one keeps some presence.

   Landing pages (homepage, About, service pages) have since opted back into
   a full first screen — see "Screen-sized sections" below. This block still
   shapes the hero on Help and the legal pages.

   The page's own rule is more specific than a bare `.hero`, so these
   carry `!important` deliberately rather than by habit.
   ------------------------------------------------------------ */
.hero {
  min-height: 0 !important;
  padding-top: calc(var(--u) * 7) !important;
  padding-bottom: calc(var(--u) * 7) !important;
}
@media (min-width: 900px) {
  .hero { min-height: 520px !important; }
}

/* The gaps between the hero's own parts. Six stacked elements each with a
   generous margin added ~104px of pure spacing on the homepage — more than
   the buttons and the trust line put together. Tightened uniformly so every
   page gains the same, rather than singling one out. */
.hero .sub { margin-top: 18px !important; }
.hero .acts { margin-top: 26px !important; }
.hero .micro { margin-top: 14px !important; }
.hero .chips { margin-top: 18px !important; }
.hero .hero-stats { margin-top: 18px !important; }

/* The hero stat block was a 2x2 grid — on the service pages, 234-261px of
   a ~680px hero column and the single tallest thing in it. One low row
   instead, so the hero states the offer and gets out of the way.

   Deliberately targeted at `.hero-stats` itself rather than at one hero
   variant: the pages use `hero-split` and `hero-center`, and the homepage
   a third arrangement, so scoping it to any one of them left the others
   with the tall block. Both cell classes (.hst on the service pages, .st
   on the homepage) are covered for the same reason.

   Four across is a narrower cell than the figures were sized for, and the
   longest of them ("3-5 days") ran past its divider, so the figure shrinks
   with the cell rather than clipping. */
@media (min-width: 900px) {
  .hero-stats {
    /* Some pages lay this out with flex, where grid-template-columns is
       simply ignored and the cells wrap to two rows — which is how one
       page kept a 249px block while the rest went to 90px. Set the
       formatting context as well as the tracks. */
    display: grid !important;
    grid-template-columns: repeat(4, minmax(0, 1fr)) !important;
    margin-top: 22px !important;
  }
  .hero-stats .hst,
  .hero-stats .st { padding: 8px 12px !important; min-width: 0; }
  .hero-stats .hst > :first-child,
  .hero-stats .st > :first-child {
    font-size: clamp(19px, 1.7vw, 26px);
    white-space: normal;
  }
}

/* Section rhythm.
   `.sec` pads 104px top and bottom, so consecutive sections sat 208px
   apart — breathing room on a dark page with light moving behind it, a
   long blank scroll on any page that has to tell a story. Halved again to
   32px a side, so consecutive sections sit about an inch apart — close
   enough to read as one continuous story rather than separate pages.
   Each page repeats the `.sec` rule in its own <style>, which loads after
   this file — hence !important rather than specificity. */
.sec { padding: calc(var(--u) * 4) 0 !important; }
@media (max-width: 720px) {
  .sec { padding: calc(var(--u) * 3) 0 !important; }
}

/* ------------------------------------------------------------
   Screen-sized heroes (landing pages)
   ------------------------------------------------------------
   Opt-in with <main class="screens">: the homepage, About and the service
   pages. The hero fills the first screen under the nav with its content
   centred. Sections below it keep their natural height: stretching a short
   one such as "How it works" to a full screen only added empty space.

   The app layout loads this file too, which is why this is opt-in.

   svh, not vh: on phones vh is the height with the address bar hidden, so a
   "full screen" overshoots whenever the bar shows. The vh line is the
   fallback for browsers without svh.

   Grid, not flex: the homepage hero is a plain block and the service
   heroes are flex rows; a one-column grid centres both without changing
   how their children size. minmax(0, 1fr) keeps a wide child (a rail, a
   long word) from stretching the column past a phone's width. */
.screens > .hero {
  display: grid !important;
  grid-template-columns: minmax(0, 1fr);
  align-content: center;
  min-height: calc(100vh - 104px) !important;
  min-height: calc(100svh - 104px) !important;
}

/* "Sign in" sits with the nav links, not with the call to action: it is the
   quiet door for people who already have an account, and should not compete
   with "Start a project" for a first-time visitor's attention. */
.topnav-links a.nav-signin { color: rgba(var(--ink-rgb), .82) !important; }
.topnav-links a.nav-signin:hover { color: var(--ink) !important; }
.tm-signin {
  display: block; padding: 12px 4px; margin-top: 4px;
  font-size: 15px; color: var(--ink-3); text-decoration: none;
  border-top: 1px solid var(--line);
}


/* Dark keeps the lifted-glass field: against a near-black ground a pale wash
   reads as a surface you can type on, where a bordered white box would glare. */
:root[data-theme="dark"] .cform .fi {
  background-color: rgba(var(--surface-rgb), .06);
  border-color: var(--glass-border);
}
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .cform .fi {
    background-color: rgba(var(--surface-rgb), .06);
    border-color: var(--glass-border);
  }
}

/* On the dark ground the field lifts slightly when focused, which is what a
   pale wash does well there. */
:root[data-theme="dark"] .cform .fi:focus { background-color: rgba(var(--surface-rgb), .09); }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .cform .fi:focus { background-color: rgba(var(--surface-rgb), .09); }
}

/* ------------------------------------------------------------
   Autofilled fields
   ------------------------------------------------------------
   A browser that fills a field for you paints it itself: Chrome ignores
   `background-color` outright and applies its own pale wash plus its own
   text colour. Nothing in the page's styling reaches it. On a page whose
   ink is near-white — or where the browser guesses the wrong one — the
   result is pale text on a pale box that cannot be read at all, and it
   only appears once something is actually filled in, which is why it
   survives every check made on an empty form.

   The background can only be reclaimed with a large inset shadow; the
   text only with -webkit-text-fill-color. The absurd transition delay is
   the standard way to stop the yellow flash on first fill.
   ------------------------------------------------------------ */
.cform .fi:-webkit-autofill,
.cform .fi:-webkit-autofill:hover,
.cform .fi:-webkit-autofill:focus,
.cform .fi:-webkit-autofill:active,
.cform .fi:autofill {
  -webkit-text-fill-color: var(--ink);
  caret-color: var(--ink);
  -webkit-box-shadow: inset 0 0 0 1000px var(--paper-3);
          box-shadow: inset 0 0 0 1000px var(--paper-3);
  transition: background-color 9999s ease-in-out 0s;
  border-color: var(--line-2);
}
.cform .fi:-webkit-autofill:focus,
.cform .fi:autofill:focus {
  border-color: var(--champagne);
  -webkit-box-shadow: inset 0 0 0 1000px var(--paper-3), 0 0 0 3px var(--champagne-50);
          box-shadow: inset 0 0 0 1000px var(--paper-3), 0 0 0 3px var(--champagne-50);
}

/* Dark fills against the glass field rather than paper, so an autofilled
   field looks like the ones beside it instead of a white slab. */
:root[data-theme="dark"] .cform .fi:-webkit-autofill,
:root[data-theme="dark"] .cform .fi:-webkit-autofill:hover,
:root[data-theme="dark"] .cform .fi:-webkit-autofill:focus,
:root[data-theme="dark"] .cform .fi:autofill {
  -webkit-text-fill-color: var(--ink);
  -webkit-box-shadow: inset 0 0 0 1000px #191727;
          box-shadow: inset 0 0 0 1000px #191727;
  border-color: var(--glass-border);
}
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .cform .fi:-webkit-autofill,
  :root:not([data-theme="light"]) .cform .fi:-webkit-autofill:hover,
  :root:not([data-theme="light"]) .cform .fi:-webkit-autofill:focus,
  :root:not([data-theme="light"]) .cform .fi:autofill {
    -webkit-text-fill-color: var(--ink);
    -webkit-box-shadow: inset 0 0 0 1000px #191727;
            box-shadow: inset 0 0 0 1000px #191727;
    border-color: var(--glass-border);
  }
}

/* ------------------------------------------------------------
   The call-to-action row
   ------------------------------------------------------------
   Two pill buttons side by side need 348px. A 390px phone leaves 2px of
   slack, and anything narrower wraps — dropping one button onto its own
   line where it sits off-centre against the other. That ragged break is
   the alignment fault, and it happens on the most common phone widths.

   Below 480px they stack and go full width, which is a deliberate shape
   rather than an accident of wrapping. Above it, they sit centred on a
   shared baseline with matching padding — they were 30px and 28px, which
   is close enough to look like a mistake rather than a decision.
   ------------------------------------------------------------ */
.acts { align-items: center; }
.acts > .btn-hot, .acts > .btn-glass, .acts > .btn-acc { padding-left: 30px; padding-right: 30px; }

@media (max-width: 480px) {
  .acts { flex-direction: column; align-items: stretch; width: 100%; gap: 10px; }
  .acts > a, .acts > button { width: 100%; justify-content: center; }
}

/* Alternate sections take the deeper ground. Page sections declare no
   background of their own, so this reaches every page through the one
   stylesheet they all load. */
.sec:nth-of-type(even) { background: var(--band, transparent); }

/* ------------------------------------------------------------
   Running strip (hero foot, any landing page)
   ------------------------------------------------------------
   Images running along the foot of the hero, each in its own bay between
   short hairlines. The editor manages the list in the dashboard (the
   container carries data-cms-gallery); a strip with no images is not shown
   at all. site.js clones the set once so the loop meets itself, and only
   then starts it. It stops for the reader: hover or keyboard focus pauses it, a
   tap pauses it and another lets it run on, and reduced motion never starts
   it — the row scrolls by hand. */
.flat-run {
  position: relative;
  height: clamp(77px, 10.4svh, 118px);   /* 20% under the first cut: a quiet line, not a shelf */
  border-top: 1px solid var(--line); }
.flat-run:focus-visible { outline: 2px solid var(--acc); outline-offset: -2px; }
.fr-view {
  height: 100%; overflow: hidden;
  -webkit-mask-image: linear-gradient(90deg, transparent, #000 7%, #000 93%, transparent);
  mask-image: linear-gradient(90deg, transparent, #000 7%, #000 93%, transparent); }
.fr-track { display: flex; width: max-content; height: 100%; }
.flat-run.is-running .fr-track { animation: fr-x var(--fr-dur, 80s) linear infinite; }
.flat-run.is-running:focus-visible .fr-track,
.flat-run.is-paused .fr-track { animation-play-state: paused; }
@media (hover: hover) { .flat-run.is-running:hover .fr-track { animation-play-state: paused; } }
@keyframes fr-x { to { transform: translate3d(-50%, 0, 0); } }
.fr-item {
  position: relative; flex: none; height: 100%;
  display: flex; align-items: center;
  padding: 0 clamp(26px, 3vw, 52px); }
/* the divider: a short hairline between bays, not a full-height table rule */
.fr-item::after {
  content: ''; position: absolute; right: 0; top: 36%; bottom: 36%;
  width: 1px; background: var(--line); }
.fr-item img {
  border-radius: 6px;
  width: auto; height: 70%; max-width: none;
  transition: transform .5s cubic-bezier(.16, 1, .3, 1); }
@media (hover: hover) {
  .fr-item:hover img { transform: translateY(-2px) scale(1.06); }
}
@media (prefers-reduced-motion: reduce) {
  .fr-view { overflow-x: auto; scrollbar-width: none; -webkit-mask-image: none; mask-image: none; }
  .fr-item img { transition: none; }
}
/* Line art (data-ink) is ink on a clear ground, so the dark theme only turns
   the ink light. Photographs are left exactly as uploaded. */
:root[data-theme="dark"] .flat-run[data-ink] .fr-item img { filter: invert(1); }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .flat-run[data-ink] .fr-item img { filter: invert(1); }
}
/* nothing uploaded, nothing shown: no empty band at the foot of the hero */
.flat-run:not(:has(.fr-item)) { display: none; }

/* ------------------------------------------------------------
   Split hero with a running strip (service pages)
   ------------------------------------------------------------
   Copy on the left, the page's own visual on the right and, once the
   editor has added images, the running strip along the foot. On desktop
   hero and strip share one screen under the nav: the strip takes its own
   row, and a visual inside .fit-box is scaled by site.js to the room left.
   Phones stack the copy over the visual. Pages tune on top of this — tech
   pack sizes its sheet itself. */
@media (min-width: 901px) {
  .screens > .hero.hero-run {
    grid-template-rows: minmax(0, 1fr) auto;
    align-content: stretch;
    height: calc(100vh - 104px);
    height: calc(100svh - 104px);
    padding-bottom: 0 !important;
  }
  .hero-run > .hero-split {
    display: grid; grid-template-columns: minmax(0, 1.05fr) minmax(0, .95fr); grid-template-rows: minmax(0, 1fr);
    align-items: center; align-self: stretch; min-height: 0;
    gap: clamp(24px, 4vw, 56px); width: 100%; text-align: left;
  }
  .hero-run .hero-copy { min-width: 0; }
  .hero-run .hero-view {
    position: relative; min-width: 0; min-height: 0; width: 100%; align-self: stretch;
    display: flex; align-items: center; justify-content: center;
  }
  .hero-run .hero-split h1 { max-width: 16ch; margin-inline: 0; font-size: clamp(32px, min(4vw, 6.6svh), 60px); }
  .hero-run .hero-split .sub { margin-left: 0; margin-right: 0; max-width: 46ch; }
  .hero-run .hero-split .acts, .hero-run .hero-split .chips { justify-content: flex-start; }
}
@media (max-width: 900px) {
  .hero-run > .hero-split { display: grid; grid-template-columns: minmax(0, 1fr); gap: 28px; }
  .hero-run .hero-view { display: flex; justify-content: center; }
}
/* the visual keeps its design width and is scaled as one picture */
.fit-box { position: relative; max-width: 100%; }
.hero-fit { width: var(--fit-w, 600px); transform-origin: 0 0; }
@media (max-width: 900px) { .hero-fit { width: min(var(--fit-w, 600px), 100%); } }
