/* Kamathi GlobeISS Technologies Limited
   Corporate site for an infrastructure group */

/* ================= fonts (self-hosted) ================= */

/* Latin subset only. Archivo and Instrument Sans are variable faces, clamped
   to the axis ranges this stylesheet actually uses. See
   docs/design-system/tokens.md. */

@font-face {
  font-family: "Archivo";
  font-style: normal;
  font-weight: 700 900;
  font-stretch: 100% 110%;
  font-display: swap;
  src: url("/fonts/archivo-variable-latin.woff2") format("woff2");
}

@font-face {
  font-family: "Instrument Sans";
  font-style: normal;
  font-weight: 400 700;
  font-stretch: 100%;
  font-display: swap;
  src: url("/fonts/instrument-sans-variable-latin.woff2") format("woff2");
}

@font-face {
  font-family: "DM Mono";
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url("/fonts/dm-mono-400-latin.woff2") format("woff2");
}

:root {
  --white:      #FFFFFF;
  --paper:      #F4F6F2;
  --paper-2:    #E9ECE5;
  --ink:        #0A0F0C;
  --ink-2:      #39423C;
  --muted:      #6B756E;

  --green:      #0B6B3F;
  --green-dk:   #064028;
  --green-lt:   #128A52;
  --red:        #C0281B;
  --line:       #D8DCD3;
  --line-dark:  rgba(255, 255, 255, 0.18);

  --display: "Archivo", "Helvetica Neue", Arial, sans-serif;
  --body:    "Instrument Sans", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
  --mono:    "DM Mono", ui-monospace, Menlo, monospace;

  --pad: 20px;
  --max: 1180px;
}

*, *::before, *::after { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth; }

body {
  margin: 0;
  background: var(--white);
  color: var(--ink);
  font-family: var(--body);
  font-size: 17px;
  line-height: 1.62;
  -webkit-font-smoothing: antialiased;
}

img, svg { display: block; max-width: 100%; }
a { color: var(--green); }
button { font: inherit; color: inherit; }

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

.wrap {
  width: 100%;
  max-width: var(--max);
  margin: 0 auto;
  padding-left: var(--pad);
  padding-right: var(--pad);
}

/* ================= type ================= */

h1, h2, h3 {
  font-family: var(--display);
  font-weight: 800;
  font-stretch: 110%;
  line-height: 1.03;
  letter-spacing: -0.03em;
  margin: 0;
  text-wrap: balance;
}

h1 { font-size: clamp(2.4rem, 7vw, 5.1rem); }
h2 { font-size: clamp(1.9rem, 4.6vw, 3.1rem); }
h3 { font-size: 1.15rem; font-stretch: 100%; font-weight: 700; letter-spacing: -0.015em; }

p { margin: 0 0 1em; }

.eyebrow {
  display: block;
  font-family: var(--mono);
  font-size: 0.7rem;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--green);
  margin-bottom: 18px;
}

.eyebrow.on-dark { color: rgba(255, 255, 255, 0.7); }

.lede { font-size: clamp(1.08rem, 2.3vw, 1.34rem); color: var(--ink-2); max-width: 58ch; line-height: 1.55; }
.lede.on-dark { color: rgba(255, 255, 255, 0.85); }

.small { font-size: 0.85rem; color: var(--muted); }

/* ================= header ================= */

.masthead { border-bottom: 1px solid var(--line); background: var(--white); position: sticky; top: 0; z-index: 40; }

.masthead-inner {
  display: flex;
  align-items: center;
  gap: 20px;
  min-height: 76px;
  padding-top: 12px;
  padding-bottom: 12px;
}

.brand { text-decoration: none; color: var(--ink); display: flex; align-items: center; gap: 12px; flex: none; }

.brand-mark {
  width: 34px;
  height: 34px;
  flex: none;
}

.brand-name {
  font-family: var(--display);
  font-weight: 800;
  font-stretch: 110%;
  font-size: 1rem;
  letter-spacing: -0.02em;
  line-height: 1.15;
  text-transform: uppercase;
}

.brand-sub {
  font-family: var(--mono);
  font-size: 0.6rem;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--muted);
  margin-top: 2px;
}

.masthead-nav { display: flex; align-items: center; gap: 26px; margin-left: auto; font-size: 0.92rem; }
.masthead-nav a { color: var(--ink-2); text-decoration: none; }
.masthead-nav a:hover { color: var(--ink); }

@media (max-width: 820px) { .masthead-nav a.hide-sm { display: none; } }

/* ================= buttons ================= */

.btn {
  display: inline-flex;
  align-items: center;
  gap: 9px;
  padding: 14px 26px;
  border: 2px solid transparent;
  border-radius: 2px;
  font-weight: 700;
  font-size: 0.95rem;
  text-decoration: none;
  cursor: pointer;
  transition: background 0.15s ease, color 0.15s ease, border-color 0.15s ease;
}

.btn-solid { background: var(--green); color: var(--white); }
.btn-solid:hover { background: var(--green-dk); }

.btn-outline { border-color: var(--ink); color: var(--ink); }
.btn-outline:hover { background: var(--ink); color: var(--white); }

.btn-light { background: var(--white); color: var(--green-dk); }
.btn-light:hover { background: var(--paper-2); }

.btn-sm { padding: 10px 18px; font-size: 0.88rem; }

/* ================= bands ================= */

.band { padding: 84px 0; }
.band-dark { background: var(--green-dk); color: var(--white); }
.band-green { background: var(--green); color: var(--white); }
.band-paper { background: var(--paper); }
.band-ink { background: var(--ink); color: var(--white); }

.band-head { max-width: 62ch; margin-bottom: 48px; }

/* hero */

.hero { padding: 92px 0 88px; background: var(--green-dk); color: var(--white); position: relative; overflow: hidden; }

.hero::after {
  content: "";
  position: absolute;
  inset: 0;
  background:
    linear-gradient(180deg, transparent 0%, transparent 86%, var(--red) 86%, var(--red) 90%, transparent 90%);
  opacity: 0.5;
  pointer-events: none;
}

.hero .wrap { position: relative; z-index: 1; }
.hero h1 { max-width: 15ch; margin-bottom: 28px; }
.hero .lede { margin-bottom: 34px; }

.flagrule { display: flex; height: 6px; width: 132px; margin-bottom: 30px; }
.flagrule i { flex: 1; }
.flagrule .f1 { background: #0A0F0C; }
.flagrule .f2 { background: var(--red); }
.flagrule .f3 { background: var(--green-lt); }

/* ================= friction ledger (signature) ================= */

.ledger { border-top: 2px solid var(--ink); }

.ledger-head, .ledger-row {
  display: grid;
  grid-template-columns: 1fr;
  gap: 6px;
  padding: 22px 0;
  border-bottom: 1px solid var(--line);
}

@media (min-width: 860px) {
  .ledger-head, .ledger-row {
    grid-template-columns: 1.15fr 1.35fr 0.7fr;
    gap: 32px;
    align-items: start;
  }
}

.ledger-head {
  padding: 14px 0;
  font-family: var(--mono);
  font-size: 0.66rem;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--muted);
  border-bottom: 1px solid var(--line);
}

.ledger-row { transition: background 0.15s ease; }
.ledger-row:hover { background: var(--paper); }

.led-friction {
  font-family: var(--display);
  font-weight: 700;
  font-stretch: 105%;
  font-size: 1.16rem;
  letter-spacing: -0.02em;
  line-height: 1.2;
}

.led-answer { color: var(--ink-2); font-size: 0.97rem; }
.led-answer strong { color: var(--ink); }

.led-status {
  font-family: var(--mono);
  font-size: 0.68rem;
  letter-spacing: 0.13em;
  text-transform: uppercase;
  color: var(--green);
  padding-top: 3px;
}

.led-status.pipeline { color: var(--muted); }

/* ================= stats ================= */

.stats { display: grid; gap: 34px; }

@media (min-width: 760px) { .stats { grid-template-columns: repeat(3, 1fr); gap: 40px; } }

.stat-n {
  font-family: var(--display);
  font-weight: 800;
  font-stretch: 108%;
  font-size: clamp(2.6rem, 6vw, 3.8rem);
  letter-spacing: -0.045em;
  line-height: 0.95;
  margin-bottom: 12px;
}

.stat-l { font-size: 0.95rem; color: rgba(255, 255, 255, 0.78); max-width: 26ch; }

/* ================= portfolio ================= */

.portfolio { display: grid; gap: 20px; }

@media (min-width: 800px) { .portfolio { grid-template-columns: repeat(2, 1fr); } }

.venture {
  border: 1px solid var(--line);
  background: var(--white);
  padding: 30px;
  display: flex;
  flex-direction: column;
  border-top: 4px solid var(--green);
}

.venture.pipeline { border-top-color: var(--line); }

.venture-meta {
  display: flex;
  justify-content: space-between;
  gap: 12px;
  font-family: var(--mono);
  font-size: 0.66rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--muted);
  margin-bottom: 18px;
}

.venture h3 {
  font-family: var(--display);
  font-size: 1.85rem;
  font-weight: 800;
  font-stretch: 108%;
  letter-spacing: -0.03em;
  margin-bottom: 12px;
}

.venture-thesis {
  font-size: 1.02rem;
  color: var(--ink);
  font-weight: 600;
  margin-bottom: 12px;
  line-height: 1.4;
}

.venture p { color: var(--ink-2); font-size: 0.94rem; }
.venture a.venture-link { margin-top: auto; padding-top: 12px; font-family: var(--mono); font-size: 0.8rem; letter-spacing: 0.06em; }

/* ================= path ================= */

.path { display: grid; gap: 2px; }

@media (min-width: 820px) { .path { grid-template-columns: repeat(3, 1fr); } }

.path-step { background: rgba(255, 255, 255, 0.07); padding: 30px; border-top: 3px solid var(--green-lt); }
.path-step.later { border-top-color: rgba(255, 255, 255, 0.28); }

.path-when {
  font-family: var(--mono);
  font-size: 0.66rem;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: rgba(255, 255, 255, 0.6);
  margin-bottom: 12px;
}

.path-step h3 { color: var(--white); margin-bottom: 10px; font-size: 1.4rem; font-family: var(--display); font-weight: 800; font-stretch: 108%; }
.path-step p { color: rgba(255, 255, 255, 0.76); font-size: 0.93rem; margin: 0; }

/* ================= record ================= */

.record { border: 1px solid var(--line); background: var(--white); }

.rec-row {
  display: grid;
  grid-template-columns: 1fr;
  gap: 3px;
  padding: 16px 24px;
  border-bottom: 1px solid var(--line);
}

.rec-row:last-child { border-bottom: none; }

@media (min-width: 640px) {
  .rec-row { grid-template-columns: 250px 1fr; gap: 26px; align-items: baseline; }
}

.rec-k {
  font-family: var(--mono);
  font-size: 0.67rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--muted);
}

.rec-v { font-size: 0.96rem; }
.rec-v.mono { font-family: var(--mono); font-size: 0.9rem; }

/* ================= plain list ================= */

.plain { list-style: none; margin: 0; padding: 0; }

.plain li { padding: 20px 0; border-bottom: 1px solid var(--line); display: grid; gap: 5px; }

@media (min-width: 700px) { .plain li { grid-template-columns: 240px 1fr; gap: 30px; align-items: baseline; } }

.plain li:last-child { border-bottom: none; }
.plain .k { font-weight: 700; font-size: 0.97rem; }
.plain .v { color: var(--ink-2); font-size: 0.95rem; }

/* ================= footer ================= */

.footer { background: var(--ink); color: var(--white); padding: 62px 0 56px; }

.foot-grid { display: grid; gap: 32px; margin-bottom: 44px; }

@media (min-width: 760px) { .foot-grid { grid-template-columns: 1.6fr 1fr 1fr 1fr; gap: 36px; } }

.foot-col h4 {
  font-family: var(--mono);
  font-size: 0.66rem;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: rgba(255, 255, 255, 0.5);
  font-weight: 400;
  margin: 0 0 14px;
}

.foot-col ul { list-style: none; margin: 0; padding: 0; }
.foot-col li { margin-bottom: 9px; }
.foot-col a { color: rgba(255, 255, 255, 0.82); text-decoration: none; font-size: 0.91rem; }
.foot-col a:hover { color: var(--white); text-decoration: underline; }

.foot-legal {
  border-top: 1px solid rgba(255, 255, 255, 0.16);
  padding-top: 26px;
  font-size: 0.81rem;
  color: rgba(255, 255, 255, 0.55);
  line-height: 1.75;
}

.foot-legal p { margin: 0 0 9px; }
.foot-legal p:last-child { margin: 0; }

/* ================= doc pages ================= */

.doc { padding: 56px 0 88px; }
.doc-head { border-bottom: 2px solid var(--ink); padding-bottom: 26px; margin-bottom: 38px; }
.doc-body { max-width: 70ch; }
.doc-body h2 { font-size: clamp(1.35rem, 3.4vw, 1.8rem); margin: 40px 0 12px; }
.doc-body ul, .doc-body ol { padding-left: 22px; margin: 0 0 1em; }
.doc-body li { margin-bottom: 7px; }

/* ================= utils ================= */

.cta-row { display: flex; flex-wrap: wrap; gap: 12px; }
.mt-24 { margin-top: 24px; }
.mt-40 { margin-top: 40px; }

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

/* ==========================================================================
   EXTENSION MARKER: end of v1
   --------------------------------------------------------------------------
   Everything ABOVE this line is the v1 stylesheet. It is not modified.
   Everything BELOW is appended component work. Append only; never reach
   above the marker to change a v1 rule.
   Documented in docs/design-system/components.md.
   ========================================================================== */

/* ================= hero media ================= */

.hero-media {
  position: absolute;
  inset: 0;
  z-index: 0;
  background-image: url("/hero/poster.webp");
  background-size: cover;
  background-position: center;
  opacity: 0.3;
  pointer-events: none;
}

/* ================= nav state ================= */

.masthead-nav a[aria-current="page"] { color: var(--ink); font-weight: 600; }
.masthead-nav .btn[aria-current="page"] { background: var(--green-dk); color: var(--white); }

@media (max-width: 620px) {
  .masthead-inner { flex-wrap: wrap; gap: 10px; }
  .masthead-nav { margin-left: 0; width: 100%; gap: 18px; font-size: 0.85rem; }
}

/* ================= buttons (extension) ================= */

.btn-ghost { border-color: rgba(255, 255, 255, 0.4); color: var(--white); }
.btn-ghost:hover { border-color: var(--white); }

/* ================= grids ================= */

.duo { display: grid; gap: 20px; }
.trio { display: grid; gap: 20px; }

@media (min-width: 760px) { .duo { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 820px) { .trio { grid-template-columns: repeat(3, 1fr); } }

/* ================= tile ================= */

.tile {
  border: 1px solid var(--line);
  border-top: 4px solid var(--green);
  background: var(--white);
  padding: 28px;
}

.tile.quiet { border-top-color: var(--line); }

.tile-k {
  font-family: var(--mono);
  font-size: 0.66rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--muted);
  margin-bottom: 14px;
}

.tile h3 {
  font-family: var(--display);
  font-size: 1.45rem;
  font-weight: 800;
  font-stretch: 108%;
  letter-spacing: -0.03em;
  margin-bottom: 10px;
}

.tile p { color: var(--ink-2); font-size: 0.94rem; }
.tile p:last-child { margin-bottom: 0; }

/* ================= notice ================= */

.notice {
  border-left: 4px solid var(--green);
  background: var(--paper);
  padding: 24px 26px;
}

.notice p:last-child { margin-bottom: 0; }

/* ================= rules list ================= */

.rules { list-style: none; margin: 0; padding: 0; counter-reset: rule; }

.rules li {
  counter-increment: rule;
  padding: 22px 0 22px 52px;
  border-bottom: 1px solid var(--line);
  position: relative;
}

.rules li:last-child { border-bottom: none; }

.rules li::before {
  content: counter(rule);
  position: absolute;
  left: 0;
  top: 22px;
  font-family: var(--mono);
  font-size: 0.8rem;
  color: var(--green);
  border: 1px solid var(--line);
  width: 32px;
  height: 32px;
  display: grid;
  place-items: center;
}

.rules .k {
  font-family: var(--display);
  font-weight: 700;
  font-stretch: 105%;
  font-size: 1.16rem;
  letter-spacing: -0.02em;
  line-height: 1.2;
  margin-bottom: 6px;
}

.rules .v { color: var(--ink-2); font-size: 0.95rem; }

/* ================= pull quote ================= */

.pull {
  font-family: var(--display);
  font-weight: 800;
  font-stretch: 108%;
  font-size: clamp(1.5rem, 3.6vw, 2.3rem);
  letter-spacing: -0.03em;
  line-height: 1.15;
  max-width: 22ch;
  margin: 0;
  text-wrap: balance;
}

/* ================= placeholder marker ================= */

.ph {
  border-bottom: 1px dotted var(--red);
  color: inherit;
}

/* ================= inline styles moved to classes ================= */

/* These three rules replace the only `style` attributes the pages carried:
   the white first segment of the flagrule on a dark ground, and the two
   footer type overrides. They render identically.

   Removing those attributes is what makes `style-src 'self'` possible with no
   'unsafe-inline'. A `style` attribute is governed by style-src-attr, which
   falls back to style-src, and 'self' does not permit it. Anything added here
   that would otherwise be written inline must become a class instead.
   See docs/deployment/headers.md. */

.flagrule.on-dark .f1 { background: var(--white); }

.foot-brand { color: var(--white); font-size: 1.05rem; }

.foot-blurb {
  margin-top: 12px;
  max-width: 34ch;
  font-size: 0.86rem;
  color: rgba(255, 255, 255, 0.6);
}

/* ================= hero frame sequence ================= */

/* Everything scoped to `.is-scrub` is enhancement. /hero.js adds that class,
   and only after it has matched (min-width: 900px) and (pointer: fine) with
   no reduced-motion preference. With JavaScript off, or on any device that
   fails those tests, none of it matches and the hero is the poster-backed
   section it has always been. See docs/design-system/hero-sequence.md. */

.hero.is-scrub {
  /* The sequence is scrubbed over this height minus one viewport. The
     redesign block below reduces it to 250vh, so 150vh of travel: about 8px
     of scroll per frame for 160 frames on a 900px-tall window. Raise it for a
     slower scrub. It is not derived from the frame count, and dropping shot 1
     to 120 frames re-paces the same travel. */
  min-height: 400vh;
  /* v1 sets `overflow: hidden`, which makes .hero a scroll container and so
     stops the sticky layer inside it from ever sticking to the viewport.
     `clip` clips identically without creating one. */
  overflow: clip;
}

/* Holds ::after to the first screen. It carries the copy's scrim now rather
   than v1's red rule, and the copy is only ever on the first screen: left at
   `inset: 0` the scrim would wash the whole scrub instead of the one screen
   that has text on it. */
.hero.is-scrub::after {
  inset: 0 0 auto 0;
  height: 100vh;
}

/* The poster moves to the sticky layer so it paints at viewport scale behind
   the canvas rather than stretched over the whole section. Same URL, so still
   one request, and it carries the hero until the first frame decodes. */
.hero.is-scrub .hero-media { background-image: none; }

.hero-sticky {
  position: sticky;
  top: 0;
  height: 100vh;
  background-image: url("/hero/poster.webp");
  background-size: cover;
  background-position: center;
}

.hero-canvas { display: block; width: 100%; height: 100%; }

/* The complement of SCRUB_QUERY in hero.js, which never runs the sequence on
   anything this matches. Stated here as well as there so the browser picks
   the static image itself: a phone makes one image request rather than
   loading the poster and then having a script swap it. Change the two
   together. Where both this and reduced-motion apply, this wins, since both
   are a single static image and neither loads a frame. */
@media (max-width: 899.98px), (pointer: coarse), (pointer: none) {
  .hero-media { background-image: url("/hero/hero-mobile.webp"); }
}

/* ==========================================================================
   REDESIGN PASS: palette roles, hero, masthead, sequence, rhythm
   --------------------------------------------------------------------------
   Still below the extension marker, so still append-only: no v1 rule is
   edited. Where a v1 rule had to change behaviour it is restated here and
   wins on source order at equal specificity, or on specificity where a v1
   selector outranks it.
   Documented in docs/design-system/tokens.md and components.md.
   ========================================================================== */

/* ================= palette roles ================= */

/* Green was the primary block colour, which made the site read as
   flag-referential rather than institutional. Near-black is the ground now.
   Green is an accent: eyebrows, rules, status marks, small fills, borders and
   hover states. It fills nothing larger than a button.

   Both locked values are unchanged. #0B6B3F and #C0281B are still the
   palette; only their roles moved. Hard rule 5 is intact. */

:root {
  /* The primary dark ground. Deliberately the same near-black as --ink:
     one near-black in the palette, carrying type on light grounds and the
     ground itself on dark bands. */
  --dark:      #0A0F0C;

  /* One step up from it, for a panel or a row sitting on a dark ground.
     1.27:1 against --dark: quiet, but enough that a card reads as a card. */
  --dark-2:    #1E2822;

  /* v1's #6B756E reaches 4.78:1 on white but only 4.39:1 on --paper, and the
     mono label cluster (.small, .rec-k, .tile-k, .ledger-head, .venture-meta)
     sits on both. Darkened until the worse of the two grounds clears AA:
     5.51:1 on white, 5.07:1 on --paper. It is a neutral, so per
     docs/design-system.md it is implementation and free to move; the locked
     values are untouched. */
  --muted:     #626B65;

  /* The deep green --green-dk used to hold. Accent hover only. It is not a
     ground and no band is filled with it. */
  --green-dp:  #064028;

  /* A tint of the locked green, for accents on a near-black ground, where
     #0B6B3F reaches only 2.94:1 and #128A52 only 4.40:1. Same hue (152.6deg),
     5.35:1 on --dark. It is a shade of the locked green, not a third accent
     hue, on the same footing as --green-lt. */
  --green-br:  #149A5D;

  /* RE-POINTED, and this one line is the palette restructure.
     v1's .hero and .band-dark both read --green-dk for their ground, and v1
     is not edited, so re-pointing the token is what turns every dark band
     near-black. It no longer holds a green: the name survives only because
     frozen rules read it. New work uses --dark. */
  --green-dk:  var(--dark);
}

/* #0B6B3F is 2.94:1 on near-black, under the 3:1 a focus indicator needs.
   --green-br clears it on both grounds: 5.35:1 on --dark, 3.61:1 on white. */
:focus-visible { outline-color: var(--green-br); }

/* ================= buttons ================= */

/* v1's `.masthead-nav a` (0,1,1) outranks `.btn-solid` (0,1,0), so the nav's
   Contact button rendered its label --ink-2 on --green: 1.58:1, a failure of
   AA by a factor of three. Restating each variant one selector stronger fixes
   it wherever a .btn sits inside a scope that colours its own links, rather
   than patching the one call site. The :hover forms are needed too, because
   `.masthead-nav a:hover` is (0,2,1). */

a.btn-solid,  a.btn-solid:hover   { color: var(--white); }
a.btn-light,  a.btn-light:hover   { color: var(--dark); }
a.btn-ghost,  a.btn-ghost:hover   { color: var(--white); }
a.btn-outline                     { color: var(--ink); }
a.btn-outline:hover               { color: var(--white); }

/* v1 darkens a solid button to --green-dk on hover, which is near-black now.
   A green button is kept green when pressed. */
.btn-solid:hover { background: var(--green-dp); }

.masthead-nav .btn[aria-current="page"] { background: var(--green-dp); }

/* ================= masthead ================= */

.masthead {
  border-bottom-color: rgba(10, 15, 12, 0.10);
}

/* Solid white stays the fallback. The translucent bar is only taken where the
   blur that justifies it is actually supported: without the filter, 0.78
   alpha over a hero frame is a smeared bar, not a frosted one. */
@supports (backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px)) {
  .masthead {
    background: rgba(255, 255, 255, 0.78);
    -webkit-backdrop-filter: saturate(150%) blur(16px);
    backdrop-filter: saturate(150%) blur(16px);
  }
}

/* v1 pins .brand at `flex: none`, so a longer wordmark overflows the row
   instead of wrapping. The full name is longer than the one v1 carried. */
.brand { flex: 0 1 auto; min-width: 0; }

/* v1 leaves both spans inline, so they render on one line and .brand-sub's
   margin-top does nothing. Stacking them is what fixes the 390px overflow:
   KAMATHI GLOBEISS TECHNOLOGIES LIMITED is 38 characters and does not fit a
   390px row beside a 34px mark at any weight. */
.brand-text { display: block; }
.brand-name { display: block; }

/* --muted, not --ink-2, is what v1 gives this. On an opaque white bar that is
   5.51:1 and fine. On the translucent bar it is not: with a near-black band or
   a hero frame behind it the bar composites to about rgb(201,203,201) and
   LIMITED falls to 3.32:1, measured. Raising the bar's alpha enough to fix it
   needs 0.91, which is opaque in all but name and throws the blur away, so the
   label darkens instead. 6.3:1 on the darkest bar, 10:1 on the lightest. */
.brand-sub {
  display: block;
  margin-top: 3px;
  color: var(--ink-2);
}

@media (max-width: 430px) {
  .masthead-inner { gap: 12px; }
  .brand { gap: 9px; }
  .brand-mark { width: 28px; height: 28px; }
  .brand-name { font-size: 0.8rem; letter-spacing: -0.01em; }
  .brand-sub { font-size: 0.54rem; letter-spacing: 0.14em; }
}

/* The four nav items still fit one row at 390px. They do not at 320, where
   the Contact button ran 25px past the viewport on every page, so the row
   wraps rather than pushing the document wider than the screen. */
@media (max-width: 380px) {
  .masthead-nav { flex-wrap: wrap; gap: 12px 16px; }
  .masthead-nav .btn-sm { padding: 9px 14px; }
}

/* ================= hero ================= */

/* Was 0.3, which was as much as the frames could carry over a green fill
   without the copy losing the ground under it. Over near-black they no longer
   fight the band, and the scrim below protects the copy instead. */
.hero-media { opacity: 0.85; }

/* v1 paints a hard-edged --red band across 86-90% of this box at opacity 0.5,
   which over a dark ground never reads as red at all: it renders rust. Worse,
   the box scrolls with .hero while the masthead is sticky, so the band tracks
   up the viewport and parks directly under the masthead at around 630px of
   scroll on the static hero, and mid-scrub on the sequence. Measured at
   1440x900: document y 711-740, and the masthead is 77px tall.

   The box itself is the right layer, though. It is already absolute, already
   above .hero-media and already below .hero .wrap at z-index 1. So it stops
   being a decorative band and becomes the directional scrim the copy needs
   at 0.85 media opacity: heaviest at the top left where the h1 and lede sit,
   gone by the right edge, so the frame is at full strength across the side
   the copy never occupies. Measured ratios: docs/design-system/hero-scrim.md. */
.hero::after {
  background: linear-gradient(100deg,
    rgba(10, 15, 12, 0.86) 0%,
    rgba(10, 15, 12, 0.84) 44%,
    rgba(10, 15, 12, 0.70) 66%,
    rgba(10, 15, 12, 0.18) 80%,
    rgba(10, 15, 12, 0) 92%);
  opacity: 1;
}

/* A left-to-right scrim only works while the copy occupies the left of the
   frame. Below 760px it spans the full width, the gradient's horizontal run
   compresses to nothing useful, and the right-hand ends of the lines sit
   where the scrim has already faded. Measured on hero-mobile.webp at 390px:
   the lede fell to 3.39:1 against a lit rgb(166,126,66), a failure. So the
   scrim turns vertical at that width, holding across the copy and fading
   below it, which is the same idea rotated to the same geometry. */
@media (max-width: 760px) {
  .hero::after {
    background: linear-gradient(180deg,
      rgba(10, 15, 12, 0.80) 0%,
      rgba(10, 15, 12, 0.78) 62%,
      rgba(10, 15, 12, 0.52) 84%,
      rgba(10, 15, 12, 0.22) 95%,
      rgba(10, 15, 12, 0.10) 100%);
  }
}

/* 400vh put about 17px of scroll on each of 160 frames, which read as slow
   without adding anything. 250vh is 150vh of travel, about 8px per frame. */
.hero.is-scrub { min-height: 250vh; }

.hero .lede { max-width: 52ch; }

/* ================= sequence ================= */

/* Replaces the three numbered labels the growth band used to carry, the word
   in which is prohibited there now. The device is a three-cell rail across
   the top of every card with this card's cell lit: it states where a step
   sits in the sequence and nothing else. It is not a progress bar. Nothing
   accumulates from card to card, so there is no reading of it under which the
   third card is "further along" than the first, and no percentage to infer.
   CSS only. See docs/design-system/sequence.md. */

.seq { display: grid; gap: 1px; }

@media (min-width: 820px) { .seq { grid-template-columns: repeat(3, 1fr); } }

.seq-step {
  position: relative;
  padding: 26px 24px 24px;
  background: var(--dark-2);
  --cell-1: var(--line-dark);
  --cell-2: var(--line-dark);
  --cell-3: var(--line-dark);
}

.seq-step::before {
  content: "";
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  height: 3px;
  background: linear-gradient(90deg,
    var(--cell-1) 0 32%,
    transparent 32% 34%,
    var(--cell-2) 34% 66%,
    transparent 66% 68%,
    var(--cell-3) 68% 100%);
}

.seq-step:nth-child(1) { --cell-1: var(--green-br); }
.seq-step:nth-child(2) { --cell-2: var(--green-br); }
.seq-step:nth-child(3) { --cell-3: var(--green-br); }

.seq-when {
  font-family: var(--mono);
  font-size: 0.66rem;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: rgba(255, 255, 255, 0.62);
  margin-bottom: 10px;
}

.seq-step h3 {
  font-family: var(--display);
  font-weight: 800;
  font-stretch: 108%;
  font-size: 1.4rem;
  color: var(--white);
  margin-bottom: 9px;
}

.seq-step p { color: rgba(255, 255, 255, 0.78); font-size: 0.93rem; margin: 0; }

/* ================= on-dark accents ================= */

/* Green is the accent now, so an eyebrow on a dark band takes it rather than
   translucent white. --green-br, not --green: 5.35:1 against --dark where
   the locked value manages 2.94:1. */
.eyebrow.on-dark { color: var(--green-br); }

.lede.on-dark { color: rgba(255, 255, 255, 0.92); }

.path-step { background: var(--dark-2); border-top-color: var(--green-br); }
.path-step.later { border-top-color: var(--line-dark); }

/* ================= vertical rhythm ================= */

/* v1 is 84px on every band at every width, which reads airy rather than
   dense. These restate the v1 values at equal specificity and win on source
   order. Nothing here changes a component's internal structure. */

.band { padding: 58px 0; }
.band-head { max-width: 62ch; margin-bottom: 30px; }
.eyebrow { margin-bottom: 14px; }

/* On the interior page headers the band-head is the whole band, so its
   bottom margin is 30px of nothing above the band's own padding. */
.band-head:last-child { margin-bottom: 0; }

/* v1 gives h1 and h2 `margin: 0` and .lede no top margin, so a lede runs
   straight into the heading above it. At 84px bands the surrounding air hid
   it; at 58px it reads as a collision. */
.band-head h1 + .lede,
.band-head h2 + .lede { margin-top: 12px; }

.hero { padding: 72px 0 76px; }
.hero h1 { margin-bottom: 22px; }
.hero .lede { margin-bottom: 28px; }

.ledger-row { padding: 18px 0; }
.plain li { padding: 16px 0; }
.rules li { padding: 18px 0 18px 52px; }
.rules li::before { top: 18px; }
.rec-row { padding: 13px 24px; }

.venture { padding: 26px; }
.tile { padding: 24px; }
.notice { padding: 20px 22px; }

.portfolio, .duo, .trio { gap: 18px; }

.doc-body h2 { margin: 30px 0 10px; }
.mt-40 { margin-top: 32px; }

.footer { padding: 48px 0 44px; }
.foot-grid { margin-bottom: 32px; }
.foot-legal { padding-top: 22px; }

@media (max-width: 620px) {
  .band { padding: 40px 0; }
  .hero { padding: 48px 0 52px; }
  .band-head { margin-bottom: 24px; }
}

/* ==========================================================================
   MOTION PASS: nav affordance, scroll-driven reveals, view transitions
   --------------------------------------------------------------------------
   Appended below the redesign block, so still append-only: no v1 rule and no
   redesign rule is edited, and the three that had to change behaviour are
   restated here and win on source order or specificity, as before.

   Everything in this block is enhancement, and each part fails to nothing on
   its own terms. The reveals sit inside @supports, so an engine without a
   view() timeline never sees the only rule that could hide anything. The
   cross-page transition is an at-rule an engine that does not know it simply
   drops. The hover work is a transition over states the pages already had, so
   without transitions the states are still reached, instantly. A browser that
   implements none of the three renders the site exactly as it rendered before
   this block existed.

   No script, no inline style, no new request, no CSP directive moved.
   Documented in docs/design-system/motion.md.
   ========================================================================== */

/* ================= the hover wash ================= */

:root {
  /* One hover ground for both interactive rows. 7% of the locked #0B6B3F over
     white. The ledger row sits on a white band and the portfolio card is white
     on a --paper band, so --paper cannot serve both: shifting the card to
     --paper would dissolve it into the ground behind it. A tint reads on
     either. It is a tint of the locked green, not a fourth accent hue, which
     is the licence design-system.md gives surface colours.
     Measured on it: --ink 17.47:1, --ink-2 9.40:1, --green 5.95:1,
     --muted 4.98:1. Nothing on either component falls below AA. */
  --green-wash: #EEF5F2;
}

/* ================= masthead nav affordance ================= */

/* v1 answers a hover with --ink-2 going to --ink. On an opaque bar that is a
   legible shift; on the translucent bar it is not. Composited over a hero
   frame the bar reaches about rgb(201,203,201), where the two colours measure
   6.38:1 and 11.84:1. Both are dark, and the move from one to the other is
   very nearly invisible.

   A green LABEL would read as a change and is not available: #0B6B3F on that
   same composited bar measures 4.04:1, under the 4.5:1 AA asks of 15.6px
   text. So the state is carried by a rule instead. The same green as a
   non-text graphic needs 3:1 under WCAG 1.4.11 and has 4.04:1, and the label
   still darkens to --ink underneath it, so the state is never colour alone.

   Contact is excluded by :not(.btn). It is a filled button and answers a
   hover with its fill, in the block at the end of this file. */

.masthead-nav > a:not(.btn) { position: relative; }

/* Absolutely positioned. In flow a 2px box with no content would be an
   inline box on the line rather than a rule beneath it. */
.masthead-nav > a:not(.btn)::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  bottom: -8px;
  height: 2px;
  background: var(--green);
  transform: scaleX(0);
  transform-origin: left;
  transition: transform 0.15s ease;
}

.masthead-nav > a:not(.btn):hover::after,
.masthead-nav > a:not(.btn):focus-visible::after { transform: scaleX(1); }

/* v1 has the :hover half of this and never had the :focus-visible half, so a
   keyboard visitor got the focus ring and none of the state the mouse got. */
.masthead-nav > a:not(.btn):focus-visible { color: var(--ink); }

/* ================= scroll-driven reveals ================= */

/* The keyframes are declared unconditionally and cost nothing: a @keyframes
   rule nothing references never runs. What is gated is the only thing that
   can ever hide an element, which is the animation.

   Two gates, and both have to pass:

     @supports: an engine with no view() timeline never sees the rule, so
                every heading, row and card keeps the opacity and the position
                it is authored with. Verified in Firefox 152, which does not
                implement animation-timeline. The whole site renders at full
                opacity there, reveals and all.
     @media:    reduced motion never sees it either, and for the same reason.
                Nothing is hidden, so there is nothing to reveal.

   Declaration order inside the block is load-bearing. `animation` is a
   shorthand that resets animation-timeline to auto and animation-range to
   normal, so both longhands must follow it. Written the other way round the
   timeline is thrown away and the reveal runs once, on load, as an ordinary
   time-based animation. That is the failure mode that hides content. */

@keyframes reveal-in {
  from { opacity: 0; transform: translateY(16px); }
  to   { opacity: 1; transform: none; }
}

@supports (animation-timeline: view()) {
  @media (prefers-reduced-motion: no-preference) {

    /* Band headings, ledger rows, portfolio cards, sequence cards. 16px and a
       short range: the page settling, not things arriving. */
    .band-head,
    .ledger-row,
    .venture,
    .seq-step {
      animation: reveal-in linear both;
      animation-timeline: view();
      animation-range: entry 10% cover 30%;
    }

    /* Staggered by range, not by delay. A delay is measured forward in time,
       which a progress timeline does not have, so a stagger built from one
       only reads correctly while the visitor scrolls down and plays in the
       wrong order scrubbed back up. A later range is a later position in the
       scroll, and a position is the same in both directions. */
    .ledger-row + .ledger-row { animation-range: entry 16% cover 38%; }

    /* The hero, the masthead and the footer are excluded, and none of the
       four selectors above appears inside any of them today. This is what
       keeps that true if one ever does. */
    .hero :is(.band-head, .ledger-row, .venture, .seq-step),
    .masthead :is(.band-head, .ledger-row, .venture, .seq-step),
    .footer :is(.band-head, .ledger-row, .venture, .seq-step) { animation: none; }
  }
}

/* ================= cross-page transitions ================= */

/* Same-origin navigation inside the site crosses over instead of blanking.
   Both documents have to opt in and every document links this one stylesheet,
   so all six do. An engine that does not know the at-rule drops it and
   navigates the way it always has.

   No script is involved, so no CSP directive moves. */

@view-transition { navigation: auto; }

/* The masthead is the one component every document carries byte for byte, so
   cross-fading it against an identical copy of itself is motion that says
   nothing. Naming it lifts it out of the root snapshot into a group of its
   own, matched by name across the two documents and morphed rather than
   faded. Same place, same size on both sides, so the morph resolves to
   nothing and the bar stays put while the page under it changes. */
.masthead { view-transition-name: masthead; }

/* ================= row and card hover ================= */

/* The ledger row already answered a hover with a background. The card never
   answered one at all. Both take the same two-part answer now: the wash, and
   a 2px rule wiping down the leading edge, in the same green and over the
   same 0.15s as the nav rule. */

/* The row carries no side padding, so a rule at its leading edge would sit on
   the first glyph of the friction. The ledger moves 14px out into the wrap's
   own gutter and the head and the rows take 14px back as padding, which
   leaves every column exactly where it was, gives the rule and the wash
   somewhere to live, and keeps the 2px top rule, the hairlines and the wash
   all one width. 14px is inside the 20px gutter at every viewport, so nothing
   is pushed past the edge of the screen. */
.ledger { margin-left: -14px; margin-right: -14px; }

.ledger-head,
.ledger-row { padding-left: 14px; padding-right: 14px; }

.ledger-row,
.venture { position: relative; }

.ledger-row::before,
.venture::before {
  content: "";
  position: absolute;
  left: 0;
  top: 0;
  bottom: 0;
  width: 2px;
  background: var(--green);
  transform: scaleY(0);
  transform-origin: top;
  transition: transform 0.15s ease;
}

.ledger-row:hover::before,
.venture:hover::before,
.venture:focus-within::before { transform: scaleY(1); }

/* Restates v1's --paper at equal specificity and wins on source order. */
.ledger-row:hover { background: var(--green-wash); }

.venture { transition: background 0.15s ease; }

.venture:hover,
.venture:focus-within { background: var(--green-wash); }

/* The arrow each portfolio link ends on. It is wrapped in a span purely so it
   can move without the label moving with it; the link's text is unchanged,
   character for character. inline-block because a transform does not apply to
   a non-replaced inline box. */
.venture-link .arrow {
  display: inline-block;
  transition: transform 0.15s ease;
}

.venture:hover .arrow,
.venture:focus-within .arrow { transform: translateX(4px); }

/* ================= reduced motion ================= */

/* v1's block at line 462 already collapses every transition and animation
   duration to 0.001ms with !important, so this is belt and braces rather than
   the only guard. It is written out because the intent should not have to be
   inferred from a wildcard: under this preference nothing in the block above
   moves.

   The states themselves stay reachable. transition: none does not stop
   scaleX(0) becoming scaleX(1). It stops that taking time, so hover and focus
   still announce themselves, instantly. Removing the affordance instead of
   the motion would be the wrong reading of the preference.

   The three ::view-transition pseudo-elements are not matched by v1's
   `*, *::before, *::after`, so they do need stating. With no animation on the
   group there is no morph, and with none on the old and new snapshots the new
   one is simply there, since it paints above the old. The transition then
   ends on the next frame, which is a navigation with no motion in it. */

@media (prefers-reduced-motion: reduce) {
  .masthead-nav > a:not(.btn)::after,
  .ledger-row::before,
  .venture::before,
  .venture,
  .venture-link .arrow { transition: none; }

  ::view-transition-group(*),
  ::view-transition-old(*),
  ::view-transition-new(*) { animation: none !important; }
}

/* ==========================================================================
   MASTHEAD PASS: the Contact button, and the current page's rule
   --------------------------------------------------------------------------
   Appended below the motion block, so still append-only: no v1 rule, no
   redesign rule and no motion rule is edited. Every selector here is scoped
   to .masthead-nav, so no button elsewhere on the site moves.
   Documented in docs/design-system/masthead.md.
   ========================================================================== */

/* Green filled the one button on every page, which spent the accent on the
   masthead at rest rather than on the work. Near-black is the fill now and
   green is what a hover buys. The label is the white a.btn-solid already
   pins, and it clears AA on both grounds: 19.33:1 at rest, 6.58:1 on hover.

   .masthead-nav a.btn-solid is (0,2,1), which outranks v1's .btn-solid
   (0,1,0) and the redesign's .btn-solid:hover (0,2,0). The aria-current form
   is restated alongside it because .masthead-nav .btn[aria-current="page"] is
   (0,3,0) and would otherwise hold contact.html's Contact at --green-dp. */

.masthead-nav a.btn-solid,
.masthead-nav a.btn-solid[aria-current="page"] { background: var(--dark); }

.masthead-nav a.btn-solid:hover,
.masthead-nav a.btn-solid:focus-visible { background: var(--green); }

/* The current page's rule is the same 2px bar the hover wipes in, held at
   scaleX(1) and painted near-black rather than green, so it reads as chrome
   rather than as a hover that never ends. 11.85:1 against the darkest the
   translucent bar composites to, rgb(201,203,201), well past the 3:1 a
   non-text graphic needs, and the label is still --ink and semibold
   underneath it, so the state is never carried by the rule alone. */

.masthead-nav > a:not(.btn)[aria-current="page"]::after {
  background: var(--dark);
  transform: scaleX(1);
}
