/* ============================================================
   Turtle Labs design system

   Ported from brandos.turtlelabs.co.in so the group site and the Studio
   carry the same surface as BrandOS rather than an approximation of it.
   Values here are the ones BrandOS actually ships: the 1240px measure, the
   96px section rhythm, the type scale, the three glow layers and the logo
   filter. Where a number looks oddly specific it is because it was copied
   rather than chosen.

   Loaded before each site's own stylesheet, which holds only the components
   that are genuinely its own.
   ============================================================ */

@import url('/assets/fonts/fonts.css');

/* ---- the brand palette ---------------------------------------------------
   Six hues, sampled from assets/logo.webp rather than chosen: crimson, red,
   amber, green, cyan and blue are the colours in the turtle, in the order the
   mark runs them, weighted by how much of the logo each one is.

   Everything that used to carry its own near-miss of these now points here.
   The site had three separate rainbows in play, the group's #C80018/#FF8C00
   set, Shell's #ec4b3b/#f5822a set and WebOS's, none of which was the logo
   and none of which matched the others.

   Each hue comes in two forms. The base is the logo colour and is for fills,
   bars and anything large. The -ink form is the same hue moved until it
   clears 4.5:1 on the grounds of its own theme, and is what text uses: the
   logo amber is 1.9:1 on white and unreadable as a label.
   ------------------------------------------------------------------------ */
/* ---- corners -------------------------------------------------------------
   Fixed pixel radii do not survive the range these sites are read at. 28px on
   a 390px phone is a quarter of the card width and reads as a lozenge; the
   same value on a 1440px card is a detail nobody notices. Each step scales
   with the viewport, so the proportion holds at both ends.
   ------------------------------------------------------------------------ */
:root {
  --r-xs:   clamp(6px,  0.5vw,  8px);
  --r-sm:   clamp(8px,  0.8vw, 12px);
  --r-md:   clamp(12px, 1.2vw, 18px);
  --r-lg:   clamp(14px, 1.5vw, 22px);
  --r-xl:   clamp(16px, 1.9vw, 28px);
  --r-pill: 999px;
}

:root {
  --tl-crimson: #D80012;
  --tl-red:     #FC3600;
  --tl-amber:   #FC9000;
  --tl-green:   #00A25A;
  --tl-cyan:    #00B4EA;
  --tl-blue:    #006CB4;

  --tl-crimson-ink: #E44D59;
  --tl-red-ink:     #FC3600;
  --tl-amber-ink:   #FC9000;
  --tl-green-ink:   #00A25A;
  --tl-cyan-ink:    #00B4EA;
  --tl-blue-ink:    #2F87C2;
  /* Three more, between the logo hues, for the surfaces with more than six
     things to colour. Same rule: a value per theme. */
  --tl-teal-ink:    #00B08C;
  --tl-indigo-ink:  #6285D2;
  --tl-violet-ink:  #9F76D2;

  /* The mark, left to right. One definition, referenced everywhere. */
  --tl-rainbow: linear-gradient(90deg, var(--tl-crimson), var(--tl-red),
    var(--tl-amber), var(--tl-green), var(--tl-cyan), var(--tl-blue));
}
@media (prefers-color-scheme: light) {
  :root:not([data-theme="dark"]) {
    --tl-crimson-ink: #D80012;
    --tl-red-ink:     #D82E00;
    --tl-amber-ink:   #A55E00;
    --tl-green-ink:   #007F47;
    --tl-cyan-ink:    #00799D;
    --tl-blue-ink:    #006CB4;
    --tl-teal-ink:    #007A61;
    --tl-indigo-ink:  #4B6AAD;
    --tl-violet-ink:  #7C5AA8;
  }
}
:root[data-theme="light"] {
  --tl-crimson-ink: #D80012;
  --tl-red-ink:     #D82E00;
  --tl-amber-ink:   #A55E00;
  --tl-green-ink:   #007F47;
  --tl-cyan-ink:    #00799D;
  --tl-blue-ink:    #006CB4;
  --tl-teal-ink:    #007A61;
  --tl-indigo-ink:  #4B6AAD;
  --tl-violet-ink:  #7C5AA8;
}

:root {
  --ink:246,243,236; --bg-rgb:11,11,12;
  --bg:#0B0B0C; --bg2:#141416; --card:#18181B; --text:#F6F3EC;
  --prose:#DEDAD2; --lede-c:#B8B4AE;
  --muted:#A1A1AA; --faint:#8C8C96;
  --line:rgba(var(--ink),0.12); --line2:rgba(var(--ink),0.08);
  --green:#34C759; --green-ink:#04170B; --greent:#4ADE80;
  --red:#FF6B6B; --orange:#FF8A5C; --amber:#FFB35C; --blue:#60A5FA; --cyan:#67E8F9;

  /* A client logo is usually black on white. Inverting it in the dark theme
     is what stops every mark arriving inside its own white rectangle. */
  --logo-filter: invert(1) grayscale(1) brightness(1.35);
  --header-bg: rgba(11,11,12,0.85);

  /* Venture colours, as tokens rather than fixed hex, because a value that
     reads well on near-black is often unreadable on white. Content names a
     tone and the theme decides the value. */
  --tone-red:#FF6B6B; --tone-orange:#FF8C00; --tone-amber:#FFB35C;
  --tone-yellow:#FFD666; --tone-green:#4ADE80; --tone-blue:#60A5FA;
  --tone-cyan:#67E8F9; --tone-purple:#C084FC;
  /* On near-black these already clear 4.5:1, so the ink set is the same set.
     It exists as separate tokens so a component can ask for the readable
     variant without knowing which theme it is in. */
  --tone-red-ink:#FF6B6B; --tone-orange-ink:#FF8C00; --tone-amber-ink:#FFB35C;
  --tone-yellow-ink:#FFD666; --tone-green-ink:#4ADE80; --tone-blue-ink:#60A5FA;
  --tone-cyan-ink:#67E8F9; --tone-purple-ink:#C084FC;

  --maxw: 1240px;
  --measure: 720px;
  --gap-section: clamp(72px, 8vw, 128px);

  /* The accent, under the name the component library asks for.

     tl-components.css is written against --cta / --cta-ink / --cta-text, and
     this surface had only ever defined --green / --green-ink, so every solid
     accent component fell through to its literal fallback and rendered white
     text on a white card. Declared as references rather than copies, so a
     theme that changes --green changes these too. */
  --cta: var(--green);
  --cta-ink: var(--green-ink);
  /* Accent-coloured text on the page ground. The two light blocks below
     darken it to #007842 to clear 4.5:1 on a light page; on the dark theme
     the accent itself is already legible, so it is the accent. */
  --cta-text: var(--green);

  /* Likewise the card surface, which this file calls --card and the
     components ask for as --surface, and the second hairline. */
  --surface: var(--card);
  --line2: var(--line);

  /* The tinted secondary-button ground. This file had never declared it, so
     the button fell through to the library's fallback and mixed its own; the
     contact sheet caught the resulting colour shift on the group and Useful
     Store pages. Declared here, it follows the theme's green. */
  --accent-soft: color-mix(in srgb, var(--cta) 10%, transparent);
}

@media (prefers-color-scheme: light) {
  :root:not([data-theme="dark"]) {
    --ink:24,24,27; --bg-rgb:243,250,254;
    --bg:#F3FAFE; --bg2:#FFFFFF; --card:#FFFFFF; --text:#18181B;
    --prose:#2E2E36; --lede-c:#43434C;
    --muted:#61616A; --faint:#5A5A64;
    --red:#C80018; --orange:#FF4500; --amber:#E07800; --greent:#00A86B;
    --blue:#0066B2; --cyan:#0092C8;
    --green:#00884B; --green-ink:#FFFFFF; --cta-text:#007842;
    /* Display tones: for large headings only, where WCAG asks 3:1 rather than
       4.5:1. The previous values were tuned to 4.5 and applied to everything,
       which pushed orange to brown and yellow to olive.

       Computed against the worst of every light ground in use rather than
       against white, because the group's page is #F3FAFE and values that
       cleared 3:1 on white measured 2.85:1 there. */
    --tone-red:#F0504B; --tone-orange:#D86806; --tone-amber:#BD7905;
    --tone-yellow:#AC8204; --tone-green:#089C57; --tone-blue:#2A88F4;
    --tone-cyan:#0995B1; --tone-purple:#B265E9;
    /* Ink tones: small text, labels and anything on a tinted panel. 4.5:1. */
    --tone-red-ink:#D71811; --tone-orange-ink:#AD5304; --tone-amber-ink:#966104;
    --tone-yellow-ink:#896704; --tone-green-ink:#077D46; --tone-blue-ink:#0B69D5;
    --tone-cyan-ink:#07778E; --tone-purple-ink:#9B37E2;
    --logo-filter: grayscale(1);
    --header-bg: rgba(243,250,254,0.88);
    color-scheme: light;
  }
}
:root[data-theme="light"] {
  --ink:24,24,27; --bg-rgb:243,250,254;
  --bg:#F3FAFE; --bg2:#FFFFFF; --card:#FFFFFF; --text:#18181B;
  --prose:#2E2E36; --lede-c:#43434C;
  --muted:#61616A; --faint:#5A5A64;
  --red:#C80018; --orange:#FF4500; --amber:#E07800; --greent:#00A86B;
  --blue:#0066B2; --cyan:#0092C8;
  --green:#00884B; --green-ink:#FFFFFF; --cta-text:#007842;
    /* Display tones: for large headings only, where WCAG asks 3:1 rather than
     4.5:1. The previous values were tuned to 4.5 and applied to everything,
     which pushed orange to brown and yellow to olive. */
  --tone-red:#F0504B; --tone-orange:#D86806; --tone-amber:#BD7905;
  --tone-yellow:#AC8204; --tone-green:#089C57; --tone-blue:#2A88F4;
  --tone-cyan:#0995B1; --tone-purple:#B265E9;
  /* Ink tones: small text, labels and anything on a tinted panel. 4.5:1. */
  --tone-red-ink:#D71811; --tone-orange-ink:#AD5304; --tone-amber-ink:#966104;
  --tone-yellow-ink:#896704; --tone-green-ink:#077D46; --tone-blue-ink:#0B69D5;
  --tone-cyan-ink:#07778E; --tone-purple-ink:#9B37E2;
  --logo-filter: grayscale(1);
  --header-bg: rgba(243,250,254,0.88);
  color-scheme: light;
}
html { color-scheme: dark; scroll-behavior: smooth; }
@media (prefers-reduced-motion: reduce) { html { scroll-behavior: auto; } }

*, *::before, *::after { box-sizing: border-box; }
input, textarea, select { min-width: 0; max-width: 100%; }

body {
  margin: 0; background: var(--bg); color: var(--text);
  font-family: 'Inter', system-ui, -apple-system, sans-serif;
  font-size: 16px; line-height: 1.6; overflow-x: hidden;
  -webkit-font-smoothing: antialiased;
  transition: background-color .25s ease, color .25s ease;
}
img { max-width: 100%; height: auto; }

/* The depth line: how far you have gone, in the brand spectrum. Copied from
   BrandOS, where it is driven by the scroll rather than sitting static, so it
   doubles as a reading position. It scales from the left, so with scrolling
   at the top it is a hairline and at the bottom it spans the window. */
body::before {
  content: ''; position: fixed; top: 0; left: 0; height: 3px; width: 100%;
  transform-origin: 0 50%; z-index: 200; pointer-events: none;
  background: var(--tl-rainbow);
  box-shadow: 0 1px 10px rgba(0,163,224,.45);
}
@supports (animation-timeline: scroll(root block)) {
  @media (prefers-reduced-motion: no-preference) {
    body::before { animation: tl-depth linear both; animation-timeline: scroll(root block); }
    @keyframes tl-depth { from { transform: scaleX(0); } to { transform: scaleX(1); } }
  }
}

/* The mark settles once, like something coming to rest in water. */
@supports (animation-timeline: view()) {
  @media (prefers-reduced-motion: no-preference) {
    .brand-mark { animation: tl-settle 1.1s cubic-bezier(.22,.9,.24,1) both; }
    @keyframes tl-settle { from { transform: translateY(-5px) scale(.94); opacity: 0; }
                           60%  { transform: translateY(1px) scale(1.01); opacity: 1; }
                           to   { transform: none; opacity: 1; } }
  }
}

/* ---- accent bars -------------------------------------------------------
   One shared rule for the coloured edge on a container. It fades to nothing
   across the width rather than sitting as a solid block of colour: with a
   dozen cards on screen, a dozen solid bars is a lot of colour competing for
   the same attention, and the point of the accent is to identify the card,
   not to be the loudest thing on it. Applied through a class so the number
   of containers that carry one can be limited in one place. */

.accent-bar { position: relative; }
.accent-bar::before {
  content: ''; position: absolute; inset: 0 0 auto 0; height: 2px; border-radius: 2px 2px 0 0;
  background: linear-gradient(90deg, var(--bar, var(--greent)), transparent 78%);
  opacity: .85; pointer-events: none;
}

/* ---- the water --------------------------------------------------------
   Three fixed layers behind everything, copied from BrandOS. None of them
   can affect layout or intercept a click.

   Deliberately CSS only. A canvas particle loop would look wonderful and
   cost battery on every view forever, which is a strange thing to ship
   under a carbon badge. */

@media (prefers-reduced-motion: no-preference) {
  .tl-caustic, .tl-deep, .tl-plight {
    position: fixed; inset: 0; pointer-events: none; z-index: 3; contain: strict;
  }

  /* Sunlight through moving water. Two tinted layers drift against each
     other on different periods, so the pattern never visibly repeats. */
  /* The gradients are drawn soft rather than blurred, and the drift moves
     only the transform.

     BrandOS animates background-position here as well as the transform, and
     wears a 26px blur on top. Both force the compositor to repaint a
     full-viewport blended layer on every frame: measured on this markup it
     halved the frame rate while scrolling, 28.6ms per frame against 16.7ms
     with the layer off. Moving a transform is free by comparison, and the
     result is the same light, so this is the one place worth departing from
     the original. */
  /* Still, not drifting.
     
     BrandOS animates this layer, and moving anything on a full-viewport
     mix-blend-mode surface makes the compositor re-blend the whole screen
     every frame. Measured on this page: 126ms per frame with the drift and
     35ms with the same layer held still, on the same machine in the same
     run. That is 8fps against 28, and it is what the reported lag was.
     
     Removing the blur and animating only a transform was not enough, because
     the blending is the expensive part and the animation is what forces it to
     be redone. The light is identical when it is still, so it is still. The
     page keeps its motion where motion costs nothing: the pointer glow moves
     only while the pointer does, and the depth tint is a scroll-linked
     opacity rather than a moving surface. */
  .tl-caustic {
    mix-blend-mode: screen; opacity: .42;
    background:
      radial-gradient(58% 34% at 20% 16%, rgba(0,172,231,.30), transparent 72%),
      radial-gradient(50% 30% at 76% 30%, rgba(0,157,91,.25), transparent 74%),
      radial-gradient(44% 28% at 44% 72%, rgba(0,111,177,.27), transparent 76%);
  }

  /* Descent. Cross-fades in over the scroll, so the light cools from surface
     cyan toward deep blue the further down the page you are. It tints the
     light, never darkens the page, so text contrast is untouched. */
  .tl-deep {
    mix-blend-mode: screen; opacity: 0; will-change: opacity;
    background:
      radial-gradient(60% 36% at 30% 26%, rgba(0,64,140,.36), transparent 74%),
      radial-gradient(52% 32% at 72% 62%, rgba(12,32,92,.32), transparent 76%);
    animation: tl-descend linear both;
    animation-timeline: scroll(root block);
  }
  @keyframes tl-descend { from { opacity: 0; } to { opacity: .55; } }

  /* A torch underwater. Follows the pointer, desktop only. Smaller and
     lighter than a spotlight: the page carries plenty of colour already. */
  @media (hover: hover) and (pointer: fine) {
    .tl-plight {
      mix-blend-mode: screen; opacity: .17;
      background: radial-gradient(130px 130px at var(--tl-mx, -999px) var(--tl-my, -999px),
                  rgba(var(--tl-glow, 0,163,224), .40),
                  rgba(var(--tl-glow, 0,163,224), .14) 45%, transparent 72%);
      transition: opacity .5s ease;
    }
  }
}

/* The light theme is a bright ground, so the same layers have to sit back. */
@media (prefers-color-scheme: light) {
  :root:not([data-theme="dark"]) .tl-caustic { opacity: .3; }
  :root:not([data-theme="dark"]) .tl-deep { display: none; }
  :root:not([data-theme="dark"]) .tl-plight { opacity: .12; }
}
:root[data-theme="light"] .tl-caustic { opacity: .3; }
:root[data-theme="light"] .tl-deep { display: none; }
:root[data-theme="light"] .tl-plight { opacity: .12; }

/* ---- measure and rhythm ------------------------------------------------
   BrandOS spaces sections with bottom padding only, at 96px, inside a
   1240px measure. Copied rather than re-invented so the three sites scroll
   at the same pace. */

.wrap { width: 100%; max-width: var(--maxw); margin: 0 auto; padding: 0 24px; }
main { display: block; position: relative; z-index: 4; }
/* Bottom-led, as BrandOS is, but with a little above as well: with no top
   padding a heading starts exactly where the previous section's content
   stopped, and dense sections read as jammed together. */
.band { padding: clamp(20px, 2.6vw, 40px) 24px var(--gap-section); }
/* BrandOS opens with padding:96px 24px on the first section and 0 24px 96px
   on the rest, so the first one is not pressed against the hero. */
.hero + .band, .marks-band + .band { padding-top: var(--gap-section); }
.head { padding: clamp(48px, 7vw, 88px) 24px clamp(16px, 2vw, 26px); }
@media (max-width: 640px) { :root { --gap-section: 60px; } }

/* ---- type ---------------------------------------------------------------- */

h1, h2, h3, h4 { font-family: 'Outfit', sans-serif; letter-spacing: -0.03em; line-height: 1.08; }
h1 { font-weight: 900; font-size: clamp(42px, 7vw, 78px); margin: 0 0 22px; }
h2 { font-weight: 800; font-size: clamp(32px, 4.5vw, 50px); margin: 0 0 18px; }
h3 { font-weight: 700; font-size: clamp(20px, 2.4vw, 24px); margin: 0 0 10px; letter-spacing: -0.02em; }
p  { margin: 0 0 16px; color: var(--prose); max-width: var(--measure); }
.lede { font-size: clamp(17px, 2.1vw, 21px); line-height: 1.55; color: var(--lede-c);
        max-width: var(--measure); }
a { color: inherit; }

.eyebrow { font-size: 11.5px; font-weight: 800; letter-spacing: .12em; text-transform: uppercase;
           color: var(--faint); margin: 0 0 14px; position: relative; padding-left: 26px; }
.eyebrow::before { content: ''; position: absolute; left: 0; top: .55em; width: 16px; height: 2px;
                   background: var(--accent-line, var(--greent)); }

/* ---- heading gradients ----------------------------------------------------
   The hero keeps the full spectrum. Every heading after it takes a two-colour
   gradient that steps one place around the wheel, so a page reads as a
   progression instead of repeating the same rainbow six times.

   The stops are theme tokens rather than fixed hex. The old rule used raw
   values chosen against near-black, which meant the yellow and cyan stretches
   of a heading were close to invisible on the light theme. lib/gradient.js
   assigns the classes; nobody writes them by hand. */

.rainbow { background-image: linear-gradient(90deg, var(--g-from, var(--tone-red)),
                                                    var(--g-to,   var(--tone-orange)));
           -webkit-background-clip: text; background-clip: text; color: transparent; }

/* The hero, and only the hero.

   The rainbow is the group's signature and it only reads as one while it is
   rare. Running it across every section turned six meaningful colours into
   decoration and made the page look busy rather than considered, so the
   spectrum now appears once per page and the sections below it take a single
   colour each. */
.rainbow.spectrum { background-image: linear-gradient(90deg,
    var(--tone-red), var(--tone-orange), var(--tone-amber),
    var(--tone-green), var(--tone-blue), var(--tone-purple)); }

/* Sections: one colour, not a gradient.

   Kept as a background-image of a single stop rather than a plain colour so
   that .rainbow's background-clip still applies and nothing else has to change.
   The cycle walks the palette so consecutive sections differ, which is what the
   gradient sequence was really for. */
.hue-1 { --g-from: var(--tone-red);    --g-to: var(--tone-red); }
.hue-2 { --g-from: var(--tone-orange); --g-to: var(--tone-orange); }
.hue-3 { --g-from: var(--tone-green);  --g-to: var(--tone-green); }
.hue-4 { --g-from: var(--tone-blue);   --g-to: var(--tone-blue); }
.hue-5 { --g-from: var(--tone-cyan);   --g-to: var(--tone-cyan); }
.hue-6 { --g-from: var(--tone-purple); --g-to: var(--tone-purple); }

/* A gradient is decoration. If the browser cannot clip a background to text,
   transparent text would be invisible text, so the colour comes back. */
@supports not ((background-clip: text) or (-webkit-background-clip: text)) {
  .rainbow { background-image: none; color: var(--text); }
}

/* ---- bullets --------------------------------------------------------------
   The house list. A paragraph that could be four bullets should be four
   bullets: the objective is a quick overview, not a reading task. */

.bullets { list-style: none; padding: 0; margin: 20px 0; display: grid; gap: 10px;
           max-width: var(--measure); }
.bullets li { position: relative; padding-left: 26px; color: var(--prose); font-size: 15.5px;
              line-height: 1.5; }
.bullets li::before { content: ''; position: absolute; left: 4px; top: .58em; width: 8px; height: 8px;
                      border-radius: 50%; background: var(--bullet, var(--greent)); }
.bullets strong { color: var(--text); font-weight: 700; }
.bullets.is-two { grid-template-columns: 1fr; max-width: none; }
@media (min-width: 760px) { .bullets.is-two { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 10px 34px; } }

/* ---- buttons -----------------------------------------------------------------
   Moved to tl-components.css. The family was defined here and again in
   webos.css with different padding and an opposite secondary weight, and the
   sprint tracker loaded neither. One definition now, for all ten surfaces. */

.herobtns { display: flex; flex-wrap: wrap; gap: 12px; margin: 30px 0 0; }

/* ---- client marks -------------------------------------------------------------
   Inverted in the dark theme, which is what removes the white rectangle a
   black-on-white logo otherwise arrives inside. */

.marks-band { padding: 30px 0; border-block: 1px solid var(--line2); overflow: hidden; }
.marks-track { overflow: hidden; }
.marks { list-style: none; margin: 0; padding: 0; display: flex; align-items: center;
         gap: 40px; width: max-content; animation: tlmarquee 80s linear infinite; }
@keyframes tlmarquee { from { transform: translateX(0); } to { transform: translateX(-50%); } }
.marks li { display: flex; align-items: center; flex-shrink: 0; }
.marks img { height: 56px; width: auto; filter: var(--logo-filter); opacity: .72; }
.marks img.is-half { height: 28px; }

/* Motion is the whole point of a marquee, so with it switched off the strip
   becomes what it would otherwise be: a wrapped, centred list. */
@media (prefers-reduced-motion: reduce) {
  .marks { animation: none; width: auto; flex-wrap: wrap; justify-content: center; gap: 18px 40px; }
  .marks li[aria-hidden="true"] { display: none; }
}
@media (max-width: 700px) {
  .marks { gap: 26px; }
  .marks img { height: 38px; }
  .marks img.is-half { height: 22px; }
}

/* On /about the same marks are a grid to be read, not a strip to drift past. */
/* A wall, not a ladder.
   These marks run from 45px to 200px wide at a common height, so a wrapping
   flex row packs each line differently and the rows step down: eleven, then
   eight, then seven, with the short last row hanging. A grid gives every mark
   the same cell and centres it, so the wall reads as a matrix and the last
   row lines up with the ones above it. */
.marks.is-grid { animation: none; width: auto; margin-top: 24px;
                 display: grid; gap: 26px 18px;
                 grid-template-columns: repeat(auto-fill, minmax(148px, 1fr));
                 align-items: center; justify-items: center; }
.marks.is-grid li { justify-content: center; width: 100%; }
.marks.is-grid img { height: auto; max-height: 46px; max-width: 100%; object-fit: contain; }
.marks.is-grid li[aria-hidden="true"] { display: none; }
@media (max-width: 640px) {
  .marks.is-grid { grid-template-columns: repeat(auto-fill, minmax(104px, 1fr)); gap: 20px 14px; }
  .marks.is-grid img { max-height: 36px; }
}

/* ---- header ---------------------------------------------------------------------- */

header { position: sticky; top: 0; z-index: 50; background: var(--header-bg);
         backdrop-filter: blur(16px); border-bottom: 1px solid var(--line); }
.bar { display: flex; align-items: center; justify-content: space-between; gap: 16px;
       padding: 14px 24px; position: relative; }
.brand { display: flex; align-items: center; gap: 11px; text-decoration: none; color: var(--text);
         font-family: 'Outfit', sans-serif; font-weight: 800; font-size: 22px;
         letter-spacing: -0.03em; white-space: nowrap; min-width: 0; }
.brand-mark { display: inline-block; flex-shrink: 0; width: 36px; height: 36px;
              background-image: url('/assets/logo.webp'); background-size: auto 100%;
              background-position: left center; background-repeat: no-repeat; }
.brand-name { min-width: 0; overflow: hidden; text-overflow: ellipsis; }
header nav { display: flex; align-items: center; gap: 26px; }
header nav a { color: var(--muted); text-decoration: none; font-size: 14.5px; font-weight: 500;
               transition: color .25s ease; }
header nav a:hover, header nav a.on { color: var(--text); }
header nav a.cta { background: var(--cta, var(--green)); color: var(--cta-ink, var(--green-ink));
                   font-weight: 700; padding: 11px 20px; border-radius: 999px; font-size: 14px; }
header nav a.cta:hover { filter: brightness(1.06); color: var(--cta-ink, var(--green-ink)); }

.burger { display: none; background: none; border: 0; cursor: pointer; padding: 8px;
          flex-direction: column; gap: 5px; }
.burger span { display: block; width: 22px; height: 2px; background: var(--text); border-radius: 2px; }
.burger[aria-expanded="true"] span:nth-child(2) { opacity: 0; }

.themetoggle { position: relative; display: inline-grid; place-items: center; width: 38px; height: 38px;
               border-radius: 999px; border: 1px solid var(--line); background: var(--bg2);
               color: var(--muted); cursor: pointer; padding: 0; flex-shrink: 0;
               transition: color .25s ease, border-color .25s ease; }
.themetoggle:hover { color: var(--text); border-color: var(--text); }
.themetoggle svg { position: absolute; width: 17px; height: 17px;
                   transition: opacity .25s ease, transform .25s ease; }
.t-sun { opacity: 0; transform: rotate(-90deg) scale(.6); }
.t-moon { opacity: 1; }
:root[data-theme="light"] .t-sun { opacity: 1; transform: none; }
:root[data-theme="light"] .t-moon { opacity: 0; transform: rotate(90deg) scale(.6); }
@media (prefers-color-scheme: light) {
  :root:not([data-theme="dark"]) .t-sun { opacity: 1; transform: none; }
  :root:not([data-theme="dark"]) .t-moon { opacity: 0; transform: rotate(90deg) scale(.6); }
}
@media (prefers-reduced-motion: reduce) { .themetoggle svg { transition: none; transform: none; } }

@media (max-width: 900px) {
  .burger { display: flex; }
  .brand { font-size: 19px; gap: 9px; }
  .brand-mark { width: 32px; height: 32px; }
  header nav { position: absolute; top: 100%; left: 0; right: 0; flex-direction: column;
               align-items: stretch; gap: 0; background: var(--bg);
               border-bottom: 1px solid var(--line); padding: 8px 0 18px; display: none; }
  header nav.open { display: flex; }
  header nav a { padding: 14px 24px; font-size: 16px; border-top: 1px solid var(--line2); }
  header nav a.cta { margin: 14px 24px 0; text-align: center; border-top: 0; }
  .themetoggle { position: absolute; top: 12px; right: 64px; }
}
@media (max-width: 430px) {
  .brand-name { position: absolute; width: 1px; height: 1px; overflow: hidden;
                clip-path: inset(50%); white-space: nowrap; }
}

/* ---- forms, the old way --------------------------------------------------
   Superseded by tl-components.css. Scoped to forms that have not been moved
   across yet, so the two can coexist during the migration: without the
   :not(), `form:not(.tl-form) label { margin-bottom: 18px }` puts eighteen pixels between
   every new label and its own input.

   This block shrinks as forms move over, and goes when the last one has.
   ------------------------------------------------------------------------ */
form:not(.tl-form) label { display: block; margin-bottom: 18px; font-size: 13.5px; font-weight: 600; color: var(--text); }
form:not(.tl-form) .opt { font-weight: 400; color: var(--faint); }
form:not(.tl-form) .row { display: grid; gap: 18px; grid-template-columns: 1fr; }
@media (min-width: 620px) { form:not(.tl-form) .row { grid-template-columns: 1fr 1fr; } }
form:not(.tl-form) input[type=text], form:not(.tl-form) input[type=email], form:not(.tl-form) input:not([type]), form:not(.tl-form) textarea, form:not(.tl-form) select {
  display: block; width: 100%; margin-top: 8px; padding: 14px 16px; font: inherit; font-weight: 400;
  color: var(--text); background: var(--bg); border: 1px solid var(--line); border-radius: 14px; }
form:not(.tl-form) select { min-height: 54px; padding-right: 44px; appearance: none; -webkit-appearance: none;
  cursor: pointer;
  background-image: linear-gradient(45deg, transparent 50%, currentColor 50%),
                    linear-gradient(135deg, currentColor 50%, transparent 50%);
  background-position: calc(100% - 22px) 55%, calc(100% - 16px) 55%;
  background-size: 6px 6px, 6px 6px; background-repeat: no-repeat; }
form:not(.tl-form) select option { background: var(--bg2); color: var(--text); }
form:not(.tl-form) :is(input, textarea, select):focus-visible { outline: 2px solid var(--cta, var(--greent));
  outline-offset: 2px; border-color: var(--cta, var(--greent)); }
form:not(.tl-form) :is(input, textarea, select).bad { border-color: #FF8A8A; }
form:not(.tl-form) textarea { resize: vertical; }
form:not(.tl-form) .check { display: flex; gap: 11px; align-items: flex-start; font-weight: 400;
              font-size: 13.5px; color: var(--muted); margin: 22px 0; }
form:not(.tl-form) .check input { margin-top: 3px; flex-shrink: 0; }
form:not(.tl-form) button[type=submit] { font: inherit; font-weight: 700; font-size: 15px; cursor: pointer;
  padding: 14px 30px; border-radius: 999px; border: 1px solid var(--cta, var(--green));
  background: var(--cta, var(--green)); color: var(--cta-ink, var(--green-ink)); }
form:not(.tl-form) button[type=submit]:hover { filter: brightness(1.08); }
form:not(.tl-form) button[disabled] { opacity: .55; cursor: not-allowed; }
.hp { position: absolute; left: -9999px; width: 1px; height: 1px; opacity: 0; }
.formnote { margin: 14px 0 0; font-size: 14px; min-height: 1.2em; }
.formnote.ok { color: var(--greent); }
.formnote.err { color: #FF8A8A; }

/* ---- footer ---------------------------------------------------------------------------- */

/* No margin above it. The last band already ends on a full --gap-section,
   the footer then added 40px of margin and up to 68px of its own padding, and
   the three compounded into roughly 200px of dark nothing between the last
   thing on the page and the first thing in the footer. The rainbow rule at
   the top of the footer is the separator; it does not need a gap as well. */
footer { position: relative; z-index: 4; margin-top: 0;
         padding: clamp(34px, 3.4vw, 52px) 0 34px; }
/* The last band stops short, since the footer supplies the space below it. */
main > .band:last-child { padding-bottom: clamp(24px, 3vw, 48px); }
footer::before { content: ''; position: absolute; inset: 0 0 auto 0; height: 2px; opacity: .55;
  background: var(--tl-rainbow); }
footer .cols { display: grid; gap: 30px;
               grid-template-columns: repeat(auto-fit, minmax(min(100%, 200px), 1fr));
               padding-top: 32px; border-top: 1px solid var(--line2); }
footer h2 { font-size: 12px; letter-spacing: .1em; text-transform: uppercase; color: var(--faint);
            margin: 0 0 14px; font-family: 'Inter', sans-serif; font-weight: 700; }
footer ul { list-style: none; padding: 0; margin: 0; }
footer li { margin-bottom: 10px; }
footer a { color: var(--muted); text-decoration: none; font-size: 14.5px; }
footer a:hover { color: var(--text); }
.foot-note { color: var(--faint); font-size: 12.5px; margin-top: 16px; }
footer .fine { display: flex; gap: 16px; flex-wrap: wrap; justify-content: space-between;
               margin-top: 32px; padding-top: 24px; border-top: 1px solid var(--line2);
               color: var(--faint); font-size: 12.5px; }
.carbon { display: inline-flex; align-items: center; gap: 8px; }
.carbon i { width: 7px; height: 7px; border-radius: 50%; background: var(--greent); flex-shrink: 0; }

.foot-call { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between;
  gap: 24px 34px; padding: 44px 28px; margin-bottom: 36px; border-radius: 28px;
  border: 1px solid var(--line2); background: var(--bg2); }
.foot-call > div { flex: 1 1 420px; }
.foot-call strong { display: block; font-family: 'Outfit', sans-serif; font-weight: 800;
  font-size: clamp(26px, 3.6vw, 38px); line-height: 1.12; letter-spacing: -0.03em; margin: 10px 0 12px; }
.foot-call p { color: var(--muted); font-size: 15px; margin: 0; max-width: 52ch; }

/* ---- reveal -------------------------------------------------------------------------------- */

/* Copied from BrandOS, including the three things mine had wrong.

   It starts at 0.15 rather than 0, so a section is always faintly there and
   never reads as a blank page. It finishes at entry 30% rather than cover
   22%, so it has resolved by the time the section is worth reading rather
   than most of the way up the screen. And it sits inside an @supports guard,
   so a browser without scroll-driven animations gets no animation at all
   instead of one that runs on the document timeline. */

@keyframes tlrise { from { opacity: .15; transform: translateY(26px); } to { opacity: 1; transform: none; } }

@supports (animation-timeline: view()) {
  @media (prefers-reduced-motion: no-preference) {
    .band, .head, .hero {
      animation: tlrise linear both;
      animation-timeline: view();
      animation-range: entry 0% entry 30%;
    }
    /* The first screen is already in view on load, so it must not sit at
       0.15 waiting for a scroll that may never come. */
    .hero { animation-range: cover 0% cover 1%; }
  }
}

/* ---- icons -------------------------------------------------------------
   A drawn mark on a plate tinted with its own colour. Minimal on purpose:
   the tint is 14%, the border 28%, so a grid of four reads as one family
   rather than four competing swatches. */

.ico { display: grid; place-items: center; width: 44px; height: 44px; border-radius: 13px;
       flex-shrink: 0; color: var(--ic, var(--greent));
       background: color-mix(in srgb, var(--ic, var(--greent)) 14%, transparent);
       border: 1px solid color-mix(in srgb, var(--ic, var(--greent)) 28%, transparent);
       transition: background .3s ease, border-color .3s ease; }
.ico svg { width: 21px; height: 21px; display: block; }
@supports not (color: color-mix(in srgb, red, blue)) {
  .ico { background: rgba(var(--ink),.05); border-color: var(--line); }
}
@media (hover: hover) {
  .svc:hover .ico, .process li:hover .ico {
    background: color-mix(in srgb, var(--ic, var(--greent)) 22%, transparent);
    border-color: color-mix(in srgb, var(--ic, var(--greent)) 46%, transparent);
  }
}
@media (max-width: 640px) { .ico { width: 40px; height: 40px; border-radius: 12px; }
                            .ico svg { width: 19px; height: 19px; } }

/* A deliberate line break in a heading is for the wide view. Below that the
   heading wraps on its own and the break only makes a short orphan line. */
@media (max-width: 560px) { h1 br, h2 br { display: none; } }

/* A line break that is a hint rather than a rule. A <br> inside a heading
   breaks at every width, including the ones where the line has already
   wrapped, and the words either side of it then run together because a <br>
   is not a space. This is a space that becomes a break when there is room. */
.brk { display: inline; }
@media (min-width: 700px) { .brk { display: block; height: 0; } }
