/*
 * Sharp grey fonts, self-hosted. Both are free under the SIL Open Font License (see licenses/).
 * Files from Fontsource 5.3.0: @fontsource-variable/schibsted-grotesk and @fontsource/ibm-plex-mono.
 * In a JavaScript project you can install those packages instead; the font stacks in tokens.css
 * accept either family name.
 */

/* Schibsted Grotesk, variable 400–900: the company's voice. */
@font-face {
  font-family: 'Schibsted Grotesk';
  font-style: normal;
  font-display: swap;
  font-weight: 400 900;
  src: url('/brand/fonts/schibsted-grotesk-latin-wght-normal.woff2') format('woff2-variations');
  unicode-range: U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD;
}
@font-face {
  font-family: 'Schibsted Grotesk';
  font-style: normal;
  font-display: swap;
  font-weight: 400 900;
  src: url('/brand/fonts/schibsted-grotesk-latin-ext-wght-normal.woff2') format('woff2-variations');
  unicode-range: U+0100-02BA,U+02BD-02C5,U+02C7-02CC,U+02CE-02D7,U+02DD-02FF,U+0304,U+0308,U+0329,U+1D00-1DBF,U+1E00-1E9F,U+1EF2-1EFF,U+2020,U+20A0-20AB,U+20AD-20C0,U+2113,U+2C60-2C7F,U+A720-A7FF;
}

/* IBM Plex Mono 400 and 500: labels, numbers, dates. */
@font-face {
  font-family: 'IBM Plex Mono';
  font-style: normal;
  font-display: swap;
  font-weight: 400;
  src: url('/brand/fonts/ibm-plex-mono-latin-400-normal.woff2') format('woff2');
  unicode-range: U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD;
}
@font-face {
  font-family: 'IBM Plex Mono';
  font-style: normal;
  font-display: swap;
  font-weight: 500;
  src: url('/brand/fonts/ibm-plex-mono-latin-500-normal.woff2') format('woff2');
  unicode-range: U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD;
}

/*
 * Sharp grey brand tokens · v1.1 · 17 October 2026
 *
 * Use the roles (--sg-bg, --sg-ink, --sg-mark…) in components, never the raw greys.
 * Light is the default. Dark follows the device: each role is one light-dark() pair, so there is one
 * place to change either side. Set data-theme="light" | "dark" on <html> to choose for the visitor.
 * Browsers without light-dark() (before mid-2024) keep the light roles.
 *
 * The company has no accent color. Its one mark color is Grey 50, for the square full stop and the
 * sharp in #g. Color belongs to the work: products, ventures and clients bring their own, and it
 * stays inside their frames.
 */

:root {
  /* The greys: eleven steps evenly spaced in OKLCH lightness (0.972 → 0.215), warm, at about hue 80. */
  --sg-grey-0: #f7f5f2; /* paper */
  --sg-grey-10: #ebe9e6;
  --sg-grey-20: #dbd9d5;
  --sg-grey-30: #c5c2be;
  --sg-grey-40: #aba9a4;
  --sg-grey-50: #918e8a; /* the mark: 3.0:1 on paper, 5.4:1 on ink */
  --sg-grey-55: #85827e; /* in-between step for borders that must reach 3:1 on paper (3.5:1) */
  --sg-grey-60: #787571;
  --sg-grey-70: #5f5d5a; /* lightest grey for text on paper (6.0:1) */
  --sg-grey-80: #474541;
  --sg-grey-90: #2f2d2a;
  --sg-grey-100: #1b1917; /* ink */

  /* Night: the dark grounds. */
  --sg-night: #151411;
  --sg-night-2: #201e1b;
  --sg-night-3: #2b2925;
  --sg-night-4: #37342f;

  /* Roles · light. The @supports block below replaces each with its light-dark() pair. */
  --sg-bg: var(--sg-grey-0);
  --sg-surface: #fffefc;
  --sg-surface-2: var(--sg-grey-10);
  --sg-rule: var(--sg-grey-20); /* hairlines, decorative only */
  --sg-border: var(--sg-grey-55); /* borders that carry meaning: inputs, outlined buttons */
  --sg-ink: var(--sg-grey-100); /* text */
  --sg-ink-2: var(--sg-grey-80); /* secondary text */
  --sg-ink-3: var(--sg-grey-70); /* captions, metadata: the lightest text color */
  --sg-mark: var(--sg-grey-50); /* the square and the sharp, list squares, link underlines. The same in both themes. */
  --sg-band: var(--sg-grey-100); /* ink bands: footer, press block */
  --sg-band-2: var(--sg-grey-90);
  --sg-band-ink: var(--sg-grey-0);
  --sg-band-ink-2: var(--sg-grey-30);
  --sg-focus: var(--sg-grey-100);
  --sg-selection: var(--sg-grey-20);
  --sg-error: #b6322b; /* form errors only, never decoration (5.5:1 on paper) */

  /* The stamp: the square develops through the ramp to Grey 50 (motion/motion.css). */
  /* The stamp's steps are motion only, so they aren't mirrored in tailwind.css or tokens.json. */
  --sg-stamp-0: var(--sg-grey-0);
  --sg-stamp-1: var(--sg-grey-10);
  --sg-stamp-2: var(--sg-grey-20);
  --sg-stamp-3: var(--sg-grey-30);
  --sg-stamp-4: var(--sg-grey-40);

  /* Type: the company speaks in Schibsted Grotesk and measures in IBM Plex Mono.
     Products keep their own type, inside their own frames. */
  --sg-font-sans: 'Schibsted Grotesk', 'Schibsted Grotesk Variable', 'Helvetica Neue', Arial, sans-serif;
  --sg-font-mono: 'IBM Plex Mono', ui-monospace, 'SF Mono', Menlo, Consolas, monospace;

  /* Type scale: fluid between a 360px phone and a 1440px desktop. */
  --sg-text-display: 600 clamp(2.75rem, 1.833rem + 4.074vw, 5.5rem) / 0.98 var(--sg-font-sans);
  --sg-text-h1: 600 clamp(2.25rem, 1.833rem + 1.852vw, 3.5rem) / 1.04 var(--sg-font-sans);
  --sg-text-h2: 600 clamp(1.625rem, 1.417rem + 0.926vw, 2.25rem) / 1.12 var(--sg-font-sans);
  --sg-text-h3: 600 1.375rem / 1.27 var(--sg-font-sans);
  --sg-text-lead: 400 clamp(1.1875rem, 1.125rem + 0.278vw, 1.375rem) / 1.45 var(--sg-font-sans);
  --sg-text-body: 400 1.0625rem / 1.6 var(--sg-font-sans);
  --sg-text-small: 400 0.875rem / 1.5 var(--sg-font-sans);
  --sg-text-control: 600 0.9375rem / 1.25 var(--sg-font-sans);
  --sg-text-label: 500 0.75rem / 1.35 var(--sg-font-mono); /* uppercase, --sg-track-label */
  --sg-text-number: 500 1.625rem / 1.1 var(--sg-font-mono);
  --sg-text-stat: 500 clamp(2.5rem, 1.9rem + 2.6vw, 4rem) / 1 var(--sg-font-mono); /* the figure in a stat row */
  --sg-track-display: -0.025em; /* the wordmark's tracking */
  --sg-track-heading: -0.015em;
  --sg-track-label: 0.08em;
  --sg-track-stat: -0.02em; /* the stat figure */
  --sg-measure: 64ch; /* body text */
  --sg-measure-lead: 46ch; /* lead text */

  /* The square full stop, in em of the text it ends (fitted to Schibsted Grotesk 600). */
  --sg-square: 0.226em;
  --sg-square-gap: 0.035em;

  /* Space: a 4px base. */
  --sg-space-1: 0.25rem;
  --sg-space-2: 0.5rem;
  --sg-space-3: 0.75rem;
  --sg-space-4: 1rem;
  --sg-space-5: 1.5rem;
  --sg-space-6: 2rem;
  --sg-space-7: 3rem;
  --sg-space-8: 4rem;
  --sg-space-9: 6rem;
  --sg-space-10: 8rem;

  /* Layout */
  --sg-max: 75rem; /* 1200px of content */
  --sg-gutter: clamp(1rem, 0.333rem + 2.963vw, 3rem); /* 16px on a phone, 48px on a desktop */
  --sg-header-h: 4rem;
  --sg-target: 2.75rem; /* 44px: the smallest touch target for controls and standalone links */

  /* Shape: square ends belong to the company. No radii, no shadows. */
  --sg-radius: 0;
  --sg-hairline: 1px;
  --sg-rule-strong: 2px;

  /* Motion: the company moves in steps and eases out. It never overshoots. */
  --sg-dur-press: 120ms;
  --sg-dur-quick: 200ms;
  --sg-dur-enter: 480ms; /* the first screen arriving */
  --sg-dur-reveal: 600ms; /* a block rising into place as it scrolls into view */
  --sg-dur-stamp: 500ms;
  --sg-stagger: 40ms;
  --sg-ease: cubic-bezier(0.2, 0, 0, 1);

  color-scheme: light;
}

/* Roles · light and dark, one pair each. The grounds go to night; Grey 50 stays exactly the same.
 * color-scheme on <html> decides which side is used: the device by default, or data-theme. */
@supports (color: light-dark(#000, #fff)) {
  :root {
    color-scheme: light dark;
    --sg-bg: light-dark(var(--sg-grey-0), var(--sg-night));
    --sg-surface: light-dark(#fffefc, var(--sg-night-2));
    --sg-surface-2: light-dark(var(--sg-grey-10), var(--sg-night-3));
    --sg-rule: light-dark(var(--sg-grey-20), var(--sg-night-4));
    --sg-border: light-dark(var(--sg-grey-55), var(--sg-grey-60));
    --sg-ink: light-dark(var(--sg-grey-100), var(--sg-grey-0));
    --sg-ink-2: light-dark(var(--sg-grey-80), var(--sg-grey-20));
    --sg-ink-3: light-dark(var(--sg-grey-70), var(--sg-grey-40));
    --sg-band: light-dark(var(--sg-grey-100), var(--sg-night-2));
    --sg-band-2: light-dark(var(--sg-grey-90), var(--sg-night-3));
    --sg-focus: light-dark(var(--sg-grey-100), var(--sg-grey-0));
    --sg-selection: light-dark(var(--sg-grey-20), var(--sg-night-4));
    --sg-error: light-dark(#b6322b, #f2897c);
    --sg-stamp-0: light-dark(var(--sg-grey-0), var(--sg-night));
    --sg-stamp-1: light-dark(var(--sg-grey-10), var(--sg-grey-90));
    --sg-stamp-2: light-dark(var(--sg-grey-20), var(--sg-grey-80));
    --sg-stamp-3: light-dark(var(--sg-grey-30), var(--sg-grey-70));
    --sg-stamp-4: light-dark(var(--sg-grey-40), var(--sg-grey-60));
  }

  :root[data-theme='light'] {
    color-scheme: light;
  }

  :root[data-theme='dark'] {
    color-scheme: dark;
  }
}

/*
 * Sharp grey motion · v1.2
 *
 * The company moves in steps and eases out. It never springs, bounces or overshoots: springs belong
 * to the players in its products. The first screen arrives in order (rise, ramp in, stamp), and each
 * block below it rises into place once, the first time it scrolls into view (reveal, with
 * motion/reveal.js). Nothing moves with the scroll position and nothing animates twice. Every motion
 * here has a reduced-motion end state, and the end state is the element's normal style, so nothing
 * depends on an animation finishing.
 *
 * Needs tokens.css.
 */

/* 1. The stamp: the square full stop develops through the ramp to Grey 50, one step at a time.
 *
 *    <svg class="sg-wordmark sg-stamp">…</svg>     the inline wordmark (logo/inline/wordmark.svg)
 *    <h1 class="sg-stop sg-stamp">…</h1>           a headline that ends with the square
 *
 *    Play it once per visit, on the page's own ground (not on an ink band). Mark the element with
 *    data-sg-stamp instead of the class, and let this run in <head> before the page paints:
 *
 *      <script>try{if(!sessionStorage.getItem('sg-stamped')){document.documentElement.classList.add('sg-first');
 *      sessionStorage.setItem('sg-stamped','1')}}catch{}</script>
 *
 *    One stamp per screen. Set --sg-stamp-delay to wait for something else to arrive first. */
@property --sg-stamp-now {
  syntax: '<color>';
  inherits: false;
  initial-value: #918e8a; /* Grey 50 by hand: var() isn't allowed in @property */
}
@keyframes sg-stamp {
  0% {
    fill: var(--sg-stamp-0);
    --sg-stamp-now: var(--sg-stamp-0);
  }
  20% {
    fill: var(--sg-stamp-1);
    --sg-stamp-now: var(--sg-stamp-1);
  }
  40% {
    fill: var(--sg-stamp-2);
    --sg-stamp-now: var(--sg-stamp-2);
  }
  60% {
    fill: var(--sg-stamp-3);
    --sg-stamp-now: var(--sg-stamp-3);
  }
  80% {
    fill: var(--sg-stamp-4);
    --sg-stamp-now: var(--sg-stamp-4);
  }
  100% {
    fill: var(--sg-mark);
    --sg-stamp-now: var(--sg-mark);
  }
}
.sg-stamp .sg-sq,
.sg-stop.sg-stamp::after,
.sg-first [data-sg-stamp] .sg-sq,
.sg-first .sg-stop[data-sg-stamp]::after {
  animation: sg-stamp var(--sg-dur-stamp) step-end var(--sg-stamp-delay, 240ms) both;
}

/* 2. The first ramp on a page arrives one band at a time, from its light end. <div class="sg-ramp sg-ramp-in"> */
@keyframes sg-ramp-in {
  from {
    clip-path: inset(0 100% 0 0);
  }
  to {
    clip-path: inset(0 0 0 0);
  }
}
@keyframes sg-ramp-in-back {
  from {
    clip-path: inset(0 0 0 100%);
  }
  to {
    clip-path: inset(0 0 0 0);
  }
}
.sg-ramp-in {
  animation: sg-ramp-in calc(11 * var(--sg-stagger) * 2) steps(11, end) var(--sg-ramp-delay, 0ms) both;
}
.sg-ramp--back.sg-ramp-in {
  animation-name: sg-ramp-in-back;
}

/* 3. Rise: the first screen's content arrives. Stagger at most three items with --i: 0, 1, 2. */
@keyframes sg-rise {
  from {
    opacity: 0;
    transform: translateY(1rem);
  }
}
.sg-rise {
  animation: sg-rise var(--sg-dur-enter) var(--sg-ease) calc(var(--i, 0) * 90ms) both;
}

/* A page head (sg-head) arrives the same way without classes: its margin, then the headline,
 * then the first paragraph, and the ramp under it steps in as they land. */
.sg-head > .sg-head-margin,
.sg-head > .sg-head-text > * {
  animation: sg-rise var(--sg-dur-enter) var(--sg-ease) both;
}
.sg-head > .sg-head-text > :nth-child(1) {
  animation-delay: 90ms;
}
.sg-head > .sg-head-text > :nth-child(2) {
  animation-delay: 180ms;
}
.sg-head > .sg-head-text > :nth-child(n + 3) {
  animation-delay: 270ms;
}
.sg-head + .sg-ramp {
  animation: sg-ramp-in calc(11 * var(--sg-stagger) * 2) steps(11, end) 240ms both;
}

/* 5. Reveal: below the first screen, each block rises into place once, the first time it
 *    scrolls into view, and blocks that arrive together follow each other 70 ms apart. A ramp
 *    steps in from its light end instead. motion/reveal.js adds these classes, and only to
 *    what starts below the screen, so without it nothing is ever hidden.
 *      <script src="motion/reveal.js" defer></script> */
.sg-reveal {
  transition:
    opacity var(--sg-dur-reveal) var(--sg-ease) var(--sg-reveal-delay, 0ms),
    transform var(--sg-dur-reveal) var(--sg-ease) var(--sg-reveal-delay, 0ms);
}
.sg-reveal--pending {
  opacity: 0;
  transform: translateY(1rem);
}
/* The ramp is hidden with a mask, not clipped: a clipped ramp has no area, and the browser would
 * never see it come into view. The mask grows one band at a time from the light end. */
.sg-ramp.sg-reveal {
  mask-image: linear-gradient(#000, #000);
  mask-repeat: no-repeat;
  mask-position: left;
  mask-size: 100% 100%;
  transition: mask-size calc(11 * var(--sg-stagger) * 2) steps(11, end) var(--sg-reveal-delay, 0ms);
}
.sg-ramp--back.sg-reveal {
  mask-position: right;
}
.sg-ramp.sg-reveal--pending {
  opacity: 1;
  transform: none;
  mask-size: 0% 100%;
}
/* Screens that load after the page fade in instead of popping. */
.sg-img-pending {
  opacity: 0;
}
.sg-img-fade {
  transition: opacity var(--sg-dur-enter) var(--sg-ease);
}

@media print {
  .sg-reveal--pending,
  .sg-img-pending {
    opacity: 1 !important;
    transform: none !important;
    mask: none !important;
  }
}

/* 4. Wait: a square that steps through the ramp and back while something loads.
 *    <span class="sg-wait" role="status" aria-label="Loading"></span> */
.sg-wait {
  display: inline-block;
  width: 0.625rem;
  height: 0.625rem;
  vertical-align: baseline;
  background: var(--sg-stamp-now);
  animation: sg-stamp 1000ms step-end infinite alternate;
}

@media (prefers-reduced-motion: reduce) {
  .sg-stamp .sg-sq,
  .sg-stop.sg-stamp::after,
  .sg-first [data-sg-stamp] .sg-sq,
  .sg-first .sg-stop[data-sg-stamp]::after,
  .sg-ramp-in,
  .sg-rise,
  .sg-head > .sg-head-margin,
  .sg-head > .sg-head-text > *,
  .sg-head + .sg-ramp {
    animation: none;
  }
  .sg-reveal,
  .sg-img-fade {
    transition: none;
  }
  .sg-reveal--pending,
  .sg-img-pending {
    opacity: 1;
    transform: none;
    mask: none;
  }
  /* Still show that something is happening, without movement: a slow, two-step blink. */
  .sg-wait {
    animation: sg-wait-still 2000ms step-end infinite;
  }
  @keyframes sg-wait-still {
    50% {
      opacity: 0.4;
    }
  }
}

/*
 * Sharp grey base styles · v1.1 · 17 October 2026
 *
 * Plain CSS, no build step. Link this one file and it brings the fonts, the tokens and the motion:
 *   <link rel="stylesheet" href="brand/css/sharp-grey.css">
 * For production, bundle the four files (or link them in parallel) instead of chaining @imports.
 *
 * Element defaults for type and links, then a small set of sg- classes for the patterns in
 * GUIDE.md § Web. Corners are square, surfaces are flat, and there is no accent color.
 */

/* ── Base ─────────────────────────────────────────────────────────────── */

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

html {
  -webkit-text-size-adjust: 100%;
  text-size-adjust: 100%;
}

body {
  margin: 0;
  background: var(--sg-bg);
  color: var(--sg-ink);
  font: var(--sg-text-body);
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

::selection {
  background: var(--sg-selection);
  color: var(--sg-ink);
}

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

img,
svg,
video {
  display: block;
  max-width: 100%;
  height: auto;
}

h1,
h2,
h3,
h4,
p,
ul,
ol,
figure,
blockquote,
dl,
dd {
  margin: 0;
}

h1,
h2,
h3,
h4 {
  text-wrap: balance;
}

p,
li,
dd {
  text-wrap: pretty;
}

h1 {
  font: var(--sg-text-h1);
  letter-spacing: var(--sg-track-display);
}

h2 {
  font: var(--sg-text-h2);
  letter-spacing: var(--sg-track-heading);
}

h3 {
  font: var(--sg-text-h3);
  letter-spacing: var(--sg-track-heading);
}

h4 {
  font: var(--sg-text-control);
}

strong,
b {
  font-weight: 600;
}

/* The company doesn't use italics for emphasis: weight does that. Italic is kept for titles of works. */
em,
i,
cite {
  font-style: italic;
}

a {
  color: inherit;
  text-decoration-line: underline;
  text-decoration-thickness: 1px;
  text-underline-offset: 0.22em;
  text-decoration-color: var(--sg-mark);
  transition: text-decoration-color var(--sg-dur-quick) var(--sg-ease);
}

a:hover {
  text-decoration-color: currentColor;
}

hr {
  border: 0;
  border-top: var(--sg-hairline) solid var(--sg-rule);
  margin: 0;
}

code,
kbd,
samp {
  font-family: var(--sg-font-mono);
  font-size: 0.9em;
}

/* ── Type ─────────────────────────────────────────────────────────────── */

.sg-display {
  font: var(--sg-text-display);
  letter-spacing: var(--sg-track-display);
}

.sg-lead {
  font: var(--sg-text-lead);
  color: var(--sg-ink-2);
  max-width: var(--sg-measure-lead);
}

.sg-body {
  max-width: var(--sg-measure);
}

.sg-body > * + * {
  margin-top: 1em;
}

.sg-small {
  font: var(--sg-text-small);
  color: var(--sg-ink-3);
}

/* Labels: uppercase mono. Never put the company name in a label: write "Sharp grey" in running text. */
.sg-label {
  font: var(--sg-text-label);
  letter-spacing: var(--sg-track-label);
  text-transform: uppercase;
  color: var(--sg-ink-3);
}

.sg-number {
  font: var(--sg-text-number);
  font-variant-numeric: tabular-nums;
}

.sg-mono {
  font-family: var(--sg-font-mono);
  font-variant-numeric: tabular-nums;
}

/* The square full stop. Write the headline without its full stop and add the class:
 *   <h1 class="sg-display sg-stop">Grey areas, made sharp</h1>
 * The square is drawn on an inline word joiner, so it can never wrap onto a line by itself.
 * Display and h1 headlines only, one per screen. The one-color linear-gradient is only a way to
 * size a solid square (background-color can't be sized); it isn't a gradient in the brand's sense. */
.sg-stop::after {
  content: '\2060';
  letter-spacing: 0;
  padding-left: calc(var(--sg-square-gap) + var(--sg-square));
  /* 0.2578em: Schibsted Grotesk's descent, so the square's foot sits on the baseline. */
  background: linear-gradient(var(--sg-stamp-now, var(--sg-mark)), var(--sg-stamp-now, var(--sg-mark))) no-repeat
    right 0 bottom 0.2578em / var(--sg-square) var(--sg-square);
}

/* ── Layout ───────────────────────────────────────────────────────────── */

.sg-page {
  width: 100%;
  max-width: calc(var(--sg-max) + 2 * var(--sg-gutter));
  margin-inline: auto;
  padding-inline: var(--sg-gutter);
}

/* Sections are divided by a ramp (see Graphics) or by a change of ground, never by a hairline.
 * A break that isn't worth a ramp isn't worth a break: merge the sections instead. */
.sg-section {
  padding-block: clamp(3rem, 2.33rem + 2.96vw, 5rem);
}

/* A section head is an h2 in plain words. Nothing sits above it: the section's ramp does that work. */
.sg-section-head {
  display: grid;
  gap: var(--sg-space-3);
  margin-bottom: var(--sg-space-7);
  max-width: 44rem;
}

/* The page head: the page's name in the margin (and its revision date on work pages and policies),
 * a statement that ends with the square, the first paragraph in body text, then the page's first
 * ramp. No label, no grey lead.
 *   <section class="sg-page sg-head">
 *     <p class="sg-head-margin"><span>How we work</span></p>
 *     <div class="sg-head-text"><h1 class="sg-stop">We build things to operate, not to demo</h1><p>…</p></div>
 *   </section>
 *   <div class="sg-ramp" aria-hidden="true"></div> */
.sg-head {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: var(--sg-space-5) var(--sg-space-7);
  padding-block: clamp(2rem, 1.5rem + 2vw, 3rem) clamp(2.5rem, 2rem + 2vw, 3.5rem);
}

@media (min-width: 48rem) {
  .sg-head {
    grid-template-columns: 13rem minmax(0, 44rem);
  }
}

.sg-head-margin {
  font: var(--sg-text-small);
  color: var(--sg-ink-3);
}

/* The revision date is a date, so it's set in mono. */
.sg-head-margin time {
  font-family: var(--sg-font-mono);
  font-variant-numeric: tabular-nums;
}

.sg-head-margin > span {
  display: block;
  font-weight: 500;
  color: var(--sg-ink);
}

.sg-head-text {
  display: grid;
  gap: var(--sg-space-5);
}

.sg-head-text > h1 {
  font: var(--sg-text-h1);
  letter-spacing: var(--sg-track-display);
}

.sg-head-text > p {
  max-width: var(--sg-measure);
}

.sg-stack {
  display: grid;
  gap: var(--sg-stack-gap, var(--sg-space-5));
  align-content: start;
}

.sg-cols {
  display: grid;
  gap: var(--sg-space-5);
  grid-template-columns: repeat(auto-fit, minmax(min(100%, var(--sg-col-min, 17rem)), 1fr));
}

.sg-row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--sg-space-3) var(--sg-space-5);
}

/* A text link beside a button takes the button's height, so its target is at least 44px. */
.sg-row > a:not(.sg-button) {
  display: inline-flex;
  align-items: center;
  min-height: 3rem;
}

/* ── Header ───────────────────────────────────────────────────────────── */

.sg-skip {
  position: absolute;
  left: var(--sg-gutter);
  top: -100vh;
  z-index: 10;
  display: inline-flex;
  align-items: center;
  min-height: var(--sg-target);
  padding: var(--sg-space-3) var(--sg-space-4);
  background: var(--sg-ink);
  color: var(--sg-bg);
  font: var(--sg-text-control);
}

.sg-skip:focus {
  top: var(--sg-space-3);
}

/* No hairline under the header: space separates it from the page. */
.sg-header > .sg-page {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--sg-space-3) var(--sg-space-6);
  min-height: var(--sg-header-h);
  padding-block: var(--sg-space-3);
}

.sg-home {
  display: block;
  color: var(--sg-ink);
  text-decoration: none;
  /* The clear space is two squares, and the padding takes the link to 44px. */
  padding-block: var(--sg-space-3);
}

/* The inline marks (logo/inline/*.svg): text in currentColor, the square and the sharp in the mark grey. */
.sg-text {
  fill: currentColor;
}

.sg-sq {
  fill: var(--sg-mark);
}

.sg-wordmark {
  height: 1.375rem;
  width: auto;
}

.sg-monogram {
  height: 2rem;
  width: auto;
}

/* At most five links, then an optional quiet button that starts a project. */
.sg-nav {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--sg-space-3) var(--sg-space-6);
}

.sg-nav ul {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sg-space-1) var(--sg-space-5);
  padding: 0;
  list-style: none;
}

.sg-nav a {
  display: inline-flex;
  align-items: center;
  min-height: var(--sg-target);
  font: 500 1.0625rem / 1.25 var(--sg-font-sans);
  text-decoration-color: transparent;
}

.sg-nav .sg-button {
  min-height: var(--sg-target);
  padding-inline: 1rem;
  border-width: var(--sg-hairline);
  font: var(--sg-text-control);
}

.sg-nav a:hover {
  text-decoration-color: var(--sg-mark);
}

.sg-nav a[aria-current='page'] {
  text-decoration-color: currentColor;
  text-decoration-thickness: 2px;
}

/* ── Buttons ──────────────────────────────────────────────────────────── */

.sg-button {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.5em;
  min-height: 3rem;
  padding: 0 1.375rem;
  border: var(--sg-rule-strong) solid var(--sg-ink);
  border-radius: var(--sg-radius);
  background: var(--sg-ink);
  color: var(--sg-bg);
  font: var(--sg-text-control);
  text-decoration: none;
  cursor: pointer;
  transition:
    background-color var(--sg-dur-press) var(--sg-ease),
    border-color var(--sg-dur-press) var(--sg-ease),
    color var(--sg-dur-press) var(--sg-ease);
}

.sg-button:hover {
  background: var(--sg-ink-2);
  border-color: var(--sg-ink-2);
}

.sg-button:active {
  transform: translateY(1px);
}

.sg-button--quiet {
  background: transparent;
  color: var(--sg-ink);
}

.sg-button--quiet:hover {
  background: var(--sg-surface-2);
  border-color: var(--sg-ink);
}

.sg-button[disabled],
.sg-button[aria-disabled='true'] {
  opacity: 0.45;
  cursor: not-allowed;
  transform: none;
}

/* ── Surfaces ─────────────────────────────────────────────────────────── */

.sg-card {
  display: grid;
  gap: var(--sg-space-4);
  align-content: start;
  padding: var(--sg-space-6);
  background: var(--sg-surface);
  border: var(--sg-hairline) solid var(--sg-rule);
}

/* An ink band: footer, press block, a closing call to action. The roles flip inside it, so links,
 * buttons and labels follow without their own variants. Don't play the stamp on a band. */
.sg-band {
  --sg-bg: var(--sg-band);
  --sg-surface: var(--sg-band-2);
  --sg-surface-2: var(--sg-band-2);
  --sg-rule: var(--sg-band-2);
  --sg-border: var(--sg-grey-60);
  --sg-ink: var(--sg-band-ink);
  --sg-ink-2: var(--sg-band-ink-2);
  --sg-ink-3: var(--sg-band-ink-2);
  --sg-focus: var(--sg-band-ink);
  --sg-selection: var(--sg-grey-80);
  background: var(--sg-bg);
  color: var(--sg-ink);
}

/* A ground: one section on Grey 10 instead of the paper, for the block that should sit forward,
 * such as the figures. It still takes a ramp above and below. It's never ink: the footer is the
 * only band. */
.sg-ground {
  background: var(--sg-surface-2);
}

/* Screenshots and product images: flat, square, a hairline. No device frames, no shadows. */
.sg-frame {
  background: var(--sg-surface);
  border: var(--sg-hairline) solid var(--sg-rule);
}

.sg-frame > img,
.sg-frame > video {
  width: 100%;
}

/* Photographs: black and white, warmed by the paper underneath. The figure's own paper ground is
 * what the photo multiplies onto, so it still reads as a paper print on a night page.
 * <figure class="sg-photo"><img src="…" alt="…"></figure> */
.sg-photo {
  background: var(--sg-grey-0);
}

.sg-photo > img {
  width: 100%;
  filter: grayscale(1) contrast(0.96);
  mix-blend-mode: multiply;
}

/* ── Graphics ─────────────────────────────────────────────────────────── */

/* The ramp: the eleven greys, in order, light to dark. The company's only "color" moment, and the
 * only thing that divides sections. 12px tall, full bleed. The first ramp on a page runs left to
 * right; every one after it turns (sg-ramp--back), so a page reads as a serpentine.
 *   <div class="sg-ramp" aria-hidden="true"></div>
 *   <div class="sg-ramp sg-ramp--back" aria-hidden="true"></div> */
.sg-ramp {
  --sg-ramp-to: right;
  height: var(--sg-ramp-h, 0.75rem);
  background: linear-gradient(
    to var(--sg-ramp-to),
    var(--sg-grey-0) 0 9.0909%,
    var(--sg-grey-10) 0 18.1818%,
    var(--sg-grey-20) 0 27.2727%,
    var(--sg-grey-30) 0 36.3636%,
    var(--sg-grey-40) 0 45.4545%,
    var(--sg-grey-50) 0 54.5454%,
    var(--sg-grey-60) 0 63.6363%,
    var(--sg-grey-70) 0 72.7272%,
    var(--sg-grey-80) 0 81.8181%,
    var(--sg-grey-90) 0 90.9090%,
    var(--sg-grey-100) 0 100%
  );
}

.sg-ramp--back {
  --sg-ramp-to: left;
}

.sg-rule-strong {
  border: 0;
  border-top: var(--sg-rule-strong) solid var(--sg-ink);
}

/* Lists with square bullets in the mark grey. */
.sg-list {
  display: grid;
  gap: var(--sg-space-2);
  padding: 0;
  list-style: none;
}

.sg-list > li {
  position: relative;
  padding-left: 1.25em;
}

.sg-list > li::before {
  content: '';
  position: absolute;
  left: 0.15em;
  top: calc(0.8em - 0.2em);
  width: 0.4em;
  height: 0.4em;
  background: var(--sg-mark);
}

/* A run-in list: 1, 2… in mono, a bold run-in head, the text after it, one column.
 *   <ol class="sg-runin"><li><strong>Numbers, not adjectives.</strong> We say what a thing does…</li></ol>
 * For an unnumbered one, use <ul class="sg-runin">. */
.sg-runin {
  display: grid;
  gap: var(--sg-space-4);
  padding: 0;
  list-style: none;
  counter-reset: sg-n;
  max-width: var(--sg-measure);
}

ol.sg-runin > li {
  counter-increment: sg-n;
}

ol.sg-runin > li::before {
  content: counter(sg-n);
  font: 500 0.9em / 1 var(--sg-font-mono);
  color: var(--sg-ink-3);
  margin-right: 0.6em;
}

.sg-runin > li > strong {
  font-weight: 600;
}

/* Numbered points in a grid: 01, 02… in mono with a hairline above each. Kept for tables of steps;
 * pages prefer sg-runin. <ol class="sg-numbered"> */
.sg-numbered {
  display: grid;
  gap: var(--sg-space-6);
  padding: 0;
  list-style: none;
  counter-reset: sg-n;
}

.sg-numbered > li {
  display: grid;
  grid-template-columns: 3rem 1fr;
  gap: var(--sg-space-1) var(--sg-space-4);
  padding-top: var(--sg-space-4);
  border-top: var(--sg-hairline) solid var(--sg-rule);
  counter-increment: sg-n;
}

.sg-numbered > li::before {
  content: counter(sg-n, decimal-leading-zero);
  grid-row: span 2;
  font: var(--sg-text-label);
  letter-spacing: var(--sg-track-label);
  color: var(--sg-ink-3);
  padding-top: 0.45em;
}

/* ── Work cards ───────────────────────────────────────────────────────── */
/* One piece of work: its own screen in a frame, the relationship label (Our product, Partnership,
 * Client, Open source), its name and one line. The work's colors stay inside the frame. */

.sg-work {
  display: grid;
  gap: var(--sg-space-4);
  align-content: start;
}

.sg-work > .sg-frame {
  aspect-ratio: 1200 / 630;
  overflow: hidden;
}

.sg-work > .sg-frame > img {
  height: 100%;
  object-fit: cover;
}

.sg-work-body {
  display: grid;
  gap: var(--sg-space-2);
}

.sg-work-body > p {
  max-width: var(--sg-measure);
}

/* The title links to the work's page; the underline appears on hover. The padding and the negative
 * margin cancel out, so the target reaches 44px without moving the text. */
.sg-work h3 a {
  display: inline-block;
  padding-block: var(--sg-space-2);
  margin-block: calc(-1 * var(--sg-space-2));
  text-decoration-color: transparent;
}

.sg-work h3 a:hover {
  text-decoration-color: currentColor;
}

/* The first piece of work at full width: the screen across the page, then the name at h1 size
 * beside its line in lead text. One per page.
 *   <article class="sg-work sg-work--feature">
 *     <div class="sg-frame"><img …></div>
 *     <div class="sg-work-body"><div class="sg-work-name"><p class="sg-label">Our product · Live</p><h3>…</h3></div><p>…</p></div>
 *   </article> */
.sg-work--feature {
  gap: var(--sg-space-5);
}

.sg-work-name {
  display: grid;
  gap: var(--sg-space-2);
}

.sg-work--feature h3 {
  font: var(--sg-text-h1);
  letter-spacing: var(--sg-track-display);
}

.sg-work--feature .sg-work-body {
  gap: var(--sg-space-4) var(--sg-space-7);
  align-items: end;
}

.sg-work--feature .sg-work-body > p {
  font: var(--sg-text-lead);
}

@media (min-width: 64rem) {
  .sg-work--feature .sg-work-body {
    grid-template-columns: minmax(0, 1fr) minmax(0, 1.6fr);
  }
}

/* ── Stats ────────────────────────────────────────────────────────────── */
/* Figures that back a claim: the number in mono under a 2px ink rule, then one plain sentence that
 * says what was counted and in which piece of work. Four at most, read from the work itself.
 *   <ul class="sg-stats"><li class="sg-stat"><span class="sg-stat-figure">38</span><p>analyzers read …</p></li></ul> */
.sg-stats {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 9rem), 1fr));
  gap: var(--sg-space-6) var(--sg-space-5);
  padding: 0;
  list-style: none;
}

.sg-stat {
  display: grid;
  gap: var(--sg-space-2);
  align-content: start;
  padding-top: var(--sg-space-4);
  border-top: var(--sg-rule-strong) solid var(--sg-ink);
}

.sg-stat-figure {
  font: var(--sg-text-stat);
  letter-spacing: var(--sg-track-stat);
  font-variant-numeric: tabular-nums;
}

.sg-stat > p {
  font: var(--sg-text-small);
  color: var(--sg-ink-2);
  max-width: 30ch;
}

@media (min-width: 48rem) {
  .sg-stat > p {
    font: var(--sg-text-body);
  }
}

/* ── Product cards ────────────────────────────────────────────────────── */
/* A product appears in its own colors inside its own frame: its icon carries its color; the card doesn't. */

.sg-product {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: var(--sg-space-4) var(--sg-space-5);
  align-items: start;
  padding: var(--sg-space-6);
  background: var(--sg-surface);
  border: var(--sg-hairline) solid var(--sg-rule);
}

.sg-product-icon {
  width: 4rem;
  height: 4rem;
}

.sg-product-body {
  display: grid;
  gap: var(--sg-space-3);
  align-content: start;
}

.sg-product-body > p {
  max-width: var(--sg-measure);
}

@media (max-width: 30rem) {
  .sg-product {
    grid-template-columns: 1fr;
  }
}

/* ── Footer ───────────────────────────────────────────────────────────── */

.sg-footer {
  padding-top: var(--sg-space-8);
}

/* The footer opens with the call to action: an h2, a lead and the page's primary button. */
.sg-footer-start {
  display: grid;
  gap: var(--sg-space-5);
  max-width: 44rem;
  padding-bottom: var(--sg-space-8);
  margin-bottom: var(--sg-space-8);
}

.sg-footer-start p {
  font: var(--sg-text-lead);
  color: var(--sg-ink-2);
  max-width: var(--sg-measure-lead);
}

.sg-footer-grid {
  display: grid;
  gap: var(--sg-space-6);
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 12rem), 1fr));
  padding-bottom: var(--sg-space-7);
}

.sg-footer ul {
  display: grid;
  padding: 0;
  list-style: none;
}

.sg-footer ul a,
.sg-legal a {
  display: inline-flex;
  align-items: center;
  min-height: var(--sg-target);
  vertical-align: middle;
}

.sg-footer a {
  text-decoration-color: transparent;
}

.sg-footer a:hover {
  text-decoration-color: currentColor;
}

.sg-legal {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--sg-space-2) var(--sg-space-5);
  padding-block: var(--sg-space-4) var(--sg-space-5);
}

/* ── Forms ────────────────────────────────────────────────────────────── */

.sg-field {
  display: grid;
  gap: var(--sg-space-2);
}

.sg-field > label {
  font: var(--sg-text-control);
}

.sg-input {
  width: 100%;
  min-height: 3rem;
  padding: var(--sg-space-3) var(--sg-space-4);
  border: var(--sg-hairline) solid var(--sg-border);
  border-radius: var(--sg-radius);
  background: var(--sg-surface);
  color: var(--sg-ink);
  font: var(--sg-text-body);
}

.sg-input:focus-visible {
  outline-offset: 0;
  border-color: var(--sg-focus);
}

textarea.sg-input {
  min-height: 8rem;
  resize: vertical;
}

.sg-input[aria-invalid='true'] {
  border-color: var(--sg-error);
}

.sg-error {
  font: var(--sg-text-small);
  color: var(--sg-error);
}

/* ── Tables ───────────────────────────────────────────────────────────── */

.sg-table {
  width: 100%;
  border-collapse: collapse;
  font: var(--sg-text-small);
}

.sg-table th {
  font: var(--sg-text-label);
  letter-spacing: var(--sg-track-label);
  text-transform: uppercase;
  color: var(--sg-ink-3);
  text-align: left;
}

.sg-table th,
.sg-table td {
  padding: var(--sg-space-3) var(--sg-space-4) var(--sg-space-3) 0;
  border-bottom: var(--sg-hairline) solid var(--sg-rule);
  vertical-align: top;
}

.sg-table td.sg-mono,
.sg-table .sg-num {
  font-family: var(--sg-font-mono);
  font-variant-numeric: tabular-nums;
  text-align: right;
}

/* A link in a cell keeps the row's height and still reaches 44px. */
.sg-table a {
  display: inline-block;
  padding-block: var(--sg-space-3);
  margin-block: calc(-1 * var(--sg-space-3));
}

/* ── Utilities ────────────────────────────────────────────────────────── */

.sg-visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

/*
 * sharpgrey.com: page-level layout on top of the kit's CSS. Everything visual comes from
 * brand/css/sharp-grey.css; this file only places things. Class names start with site-.
 */

/* ── Header: the phone menu ─────────────────────────────────────────────── */

.site-menu {
  min-height: var(--sg-target);
  padding-inline: 1rem;
  border-width: var(--sg-hairline);
}

@media (min-width: 48rem) {
  .site-menu {
    display: none;
  }
}

@media (max-width: 47.99rem) {
  .sg-nav[data-js] ul,
  .sg-nav[data-js] > .site-start {
    display: none;
  }

  .sg-nav[data-js][data-open] {
    flex-basis: 100%;
  }

  .sg-nav[data-js][data-open] ul {
    display: grid;
    flex-basis: 100%;
    gap: 0;
    margin-top: var(--sg-space-2);
    border-top: var(--sg-hairline) solid var(--sg-rule);
  }

  .sg-nav[data-js][data-open] li {
    border-bottom: var(--sg-hairline) solid var(--sg-rule);
  }

  .sg-nav[data-js][data-open] a {
    width: 100%;
    min-height: 3rem;
  }

  .sg-nav[data-js][data-open] .site-menu {
    position: absolute;
    right: var(--sg-gutter);
    top: calc((var(--sg-header-h) - var(--sg-target)) / 2);
  }

  .sg-header {
    position: relative;
  }
}

/* ── Hero ───────────────────────────────────────────────────────────────── */

.site-hero {
  padding-block: clamp(2.5rem, 1.5rem + 3.5vw, 4rem) clamp(2rem, 1.5rem + 2vw, 3rem);
}

.site-hero .sg-stack {
  --sg-stack-gap: var(--sg-space-6);
}

/* ── Work ───────────────────────────────────────────────────────────────── */

/* The work: the first piece at full width (sg-work--feature), the rest three to a row. */
.site-work {
  display: grid;
  gap: var(--sg-space-8);
}

.site-work-grid {
  --sg-col-min: 20rem;
  row-gap: var(--sg-space-7);
}

/* On the home page the work starts close under the hero, so the first screen reaches it. */
.site-first {
  padding-top: clamp(2rem, 1.5rem + 2vw, 3rem);
}

.site-first .sg-section-head {
  margin-bottom: var(--sg-space-5);
}

/* A section head with its closing link on the right. */
.site-section-head {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  align-items: baseline;
  gap: var(--sg-space-3) var(--sg-space-5);
  max-width: none;
}

.site-section-head > a {
  display: inline-flex;
  align-items: center;
  min-height: var(--sg-target);
}

/* Numbered points across the width on the home page: services two to a row, commitments four. */
.site-numbered-2 {
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 26rem), 1fr));
  gap: var(--sg-space-7);
}

/* Five services, three to a row on a wide screen. */
.site-numbered-3 {
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 20rem), 1fr));
  gap: var(--sg-space-7) var(--sg-space-6);
}

/* An item shorter than its row's tallest keeps its text under its heading. */
.site-numbered-2 > li,
.site-numbered-3 > li {
  align-content: start;
}

.site-numbered-4 {
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 15rem), 1fr));
  gap: var(--sg-space-6) var(--sg-space-5);
}

.site-numbered-4 > li {
  grid-template-columns: minmax(0, 1fr);
  align-content: start;
}

.site-numbered-4 > li::before {
  grid-row: auto;
  padding-top: 0;
}

.site-two {
  --sg-col-min: 26rem;
}

/* The work's own screen, full width in its frame, after the page's first rule and before the prose. */
.site-screen {
  margin-bottom: clamp(2.5rem, 2rem + 2vw, 3.5rem);
}

.site-screen > img {
  width: 100%;
}

/* Running text on a work or policy page. */
.site-prose {
  display: grid;
  gap: var(--sg-space-6);
  max-width: var(--sg-measure);
}

.site-prose h2 {
  margin-top: var(--sg-space-4);
}

.site-prose h2:first-child {
  margin-top: 0;
}

.site-prose p + p,
.site-prose p + ul,
.site-prose ul + p {
  margin-top: calc(-1 * var(--sg-space-3));
}

.site-prose > * + h2 {
  margin-top: var(--sg-space-2);
}

/* The facts card sits beside the prose on wide screens and above it on narrow ones. */
.site-work-layout {
  display: grid;
  gap: var(--sg-space-7);
  grid-template-columns: minmax(0, 1fr);
  align-items: start;
}

@media (min-width: 64rem) {
  .site-work-layout {
    grid-template-columns: minmax(0, 1fr) 22rem;
  }

  .site-work-layout > .sg-card {
    position: sticky;
    top: var(--sg-space-5);
  }
}

.site-facts th {
  width: 7rem;
}

/* A run-in list beside its heading on wide screens. */
.site-aside {
  --sg-col-min: 20rem;
}

/* The About page's dictionary entry and the facts block. */
.site-studio {
  margin-top: var(--sg-space-8);
}

/* Numbered points with h2 headings (service and commitment pages) keep the h3 size. */
.sg-numbered h2 {
  font: var(--sg-text-h3);
  letter-spacing: var(--sg-track-heading);
}

/* The dictionary entry on the About page. */
.site-word {
  font: var(--sg-text-h2);
  letter-spacing: var(--sg-track-heading);
}

.site-word > span {
  font: 400 1rem / 1 var(--sg-font-mono);
  letter-spacing: 0;
  color: var(--sg-ink-3);
  margin-left: 0.5rem;
}

/* ── Footer ─────────────────────────────────────────────────────────────── */

/* The footer opens with the call to action, so the page closes in one ink block. */


.site-footer-line {
  font: var(--sg-text-h3);
  letter-spacing: var(--sg-track-heading);
  max-width: 16ch;
}

/* ── Policies and plain pages ───────────────────────────────────────────── */

.site-dated {
  margin-top: var(--sg-space-6);
}

/* ── Arrival ────────────────────────────────────────────────────────────── */
/* The first screen lands in order: the hero or page head (motion.css), then the first piece of
 * work on the home page, or a work page's screen. Below it, motion/reveal.js takes over. */

.site-first .sg-section-head {
  animation: sg-rise var(--sg-dur-enter) var(--sg-ease) 270ms both;
}

.site-first .sg-work--feature,
.sg-head + .sg-ramp + .sg-section .site-screen {
  animation: sg-rise var(--sg-dur-enter) var(--sg-ease) 360ms both;
}

@media (prefers-reduced-motion: reduce) {
  .site-first .sg-section-head,
  .site-first .sg-work--feature,
  .sg-head + .sg-ramp + .sg-section .site-screen {
    animation: none;
  }
}
