/* =========================================================================
   LuxGrid Systems — design system
   Motif: construction grid / electrical schematic. Dark for brand moments
   (header, hero, contact band, footer), light for reading long service copy.
   Mobile-first; min-width media queries only.
   ========================================================================= */

/* -------------------------------------------------------------------------
   1. Self-hosted fonts
   Fontsource ships its per-subset CSS WITHOUT unicode-range, so the browser
   would pick one file and never fall back per glyph — Polish diacritics would
   break. Ranges below are copied verbatim from the package's combined CSS.
   ------------------------------------------------------------------------- */
@font-face {
  font-family: "Oswald";
  font-style: normal;
  font-weight: 600;
  font-display: swap;
  src: url("../fonts/oswald-latin-600-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: "Oswald";
  font-style: normal;
  font-weight: 600;
  font-display: swap;
  src: url("../fonts/oswald-latin-ext-600-normal.woff2") format("woff2");
  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;
}
@font-face {
  font-family: "Oswald";
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: url("../fonts/oswald-latin-700-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: "Oswald";
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: url("../fonts/oswald-latin-ext-700-normal.woff2") format("woff2");
  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;
}
@font-face {
  font-family: "Manrope";
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url("../fonts/manrope-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: "Manrope";
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url("../fonts/manrope-latin-ext-400-normal.woff2") format("woff2");
  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;
}
@font-face {
  font-family: "Manrope";
  font-style: normal;
  font-weight: 600;
  font-display: swap;
  src: url("../fonts/manrope-latin-600-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: "Manrope";
  font-style: normal;
  font-weight: 600;
  font-display: swap;
  src: url("../fonts/manrope-latin-ext-600-normal.woff2") format("woff2");
  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;
}
@font-face {
  font-family: "Manrope";
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: url("../fonts/manrope-latin-700-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: "Manrope";
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: url("../fonts/manrope-latin-ext-700-normal.woff2") format("woff2");
  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;
}

/* -------------------------------------------------------------------------
   2. Tokens
   Only the two brand surfaces (#0a0a0a, #f2f3f0) and the brand lime, with
   roles swapped by band. --accent-deep exists because #8bc53f on #f2f3f0 is
   1.9:1 and unreadable; the deep variant keeps the same hue at 4.6:1.
   ------------------------------------------------------------------------- */
:root {
  --ink: #0a0a0a;
  --ink-raised: #151515;
  --paper: #f2f3f0;
  --paper-raised: #e9eae5;

  --on-ink: #f2f3f0;
  --on-ink-dim: rgba(242, 243, 240, 0.6);
  --on-paper: #0a0a0a;
  --on-paper-dim: rgba(10, 10, 10, 0.62);

  --accent: #8bc53f;
  --accent-bright: #a3dd5a;
  --accent-deep: #4e7a14;

  --rule-ink: rgba(242, 243, 240, 0.16);
  --rule-paper: rgba(10, 10, 10, 0.14);

  /* Link and focus colours travel by inheritance rather than by a selector list. Three
     separate bugs came from a dark surface being missed off such a list, so a surface now
     declares its own palette and everything nested inside picks it up automatically. */
  --link: var(--accent-deep);
  --link-hover: var(--on-paper);
  --focus: var(--accent-deep);

  --font-display: "Oswald", "Arial Narrow", "Helvetica Neue", sans-serif;
  --font-body: "Manrope", -apple-system, BlinkMacSystemFont, "Segoe UI",
    system-ui, sans-serif;

  --rail: 1280px;
  --gutter: clamp(18px, 5vw, 64px);
  --band-pad: clamp(56px, 9vw, 128px);
  --header-h: 60px;
}

/* -------------------------------------------------------------------------
   3. Base
   ------------------------------------------------------------------------- */
*,
*::before,
*::after {
  box-sizing: border-box;
  min-width: 0;
}

html {
  overflow-x: hidden;
  scroll-behavior: smooth;
  -webkit-text-size-adjust: 100%;
}

body {
  margin: 0;
  overflow-x: hidden;
  background: var(--paper);
  color: var(--on-paper);
  font-family: var(--font-body);
  font-size: clamp(1rem, 0.97rem + 0.15vw, 1.0625rem);
  line-height: 1.65;
  font-weight: 400;
  /* room for the sticky call bar on phones */
  padding-bottom: calc(58px + env(safe-area-inset-bottom, 0px));
}

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

a {
  color: var(--link);
  text-decoration-thickness: 1px;
  text-underline-offset: 3px;
}

a:hover {
  color: var(--link-hover);
}

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

/* Every dark surface in one place. Adding a new one means adding it here, and nothing
   else — buttons keep their own colour because .btn wins on specificity over `a`. */
.band--ink,
.hero,
.masthead,
.foot,
.consent,
.callbar {
  --link: var(--accent);
  --link-hover: var(--accent-bright);
  --focus: var(--accent);
}
.callbar {
  --link: var(--ink);
  --link-hover: var(--ink);
  --focus: var(--ink);
}

h1,
h2,
h3,
h4 {
  font-family: var(--font-display);
  font-weight: 700;
  line-height: 1;
  letter-spacing: -0.01em;
  text-transform: uppercase;
  margin: 0;
}

p {
  margin: 0 0 1em;
}

.skip {
  position: absolute;
  left: -9999px;
  top: 0;
  background: var(--accent);
  color: var(--ink);
  padding: 12px 18px;
  font-weight: 700;
  z-index: 100;
}
.skip:focus {
  left: 0;
}

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

/* -------------------------------------------------------------------------
   4. Layout primitives
   ------------------------------------------------------------------------- */
.rail {
  width: 100%;
  max-width: var(--rail);
  margin-inline: auto;
  padding-inline: var(--gutter);
}

.band {
  position: relative;
  padding-block: var(--band-pad);
}

.band--ink {
  background: var(--ink);
  color: var(--on-ink);
}


.band--paper {
  background: var(--paper);
  color: var(--on-paper);
}

/* Measurement ticks. Inherits colour from the band via currentColor. */
.ticks {
  height: 7px;
  opacity: 0.3;
  background-image: repeating-linear-gradient(
    to right,
    currentColor 0 1px,
    transparent 1px 12px
  );
}

/* Registration marks, like a printer's crop guides. */
.marks {
  position: relative;
}
.marks::before,
.marks::after {
  content: "";
  position: absolute;
  width: 11px;
  height: 11px;
  pointer-events: none;
  opacity: 0;
  transition: opacity 0.18s ease;
}
.marks::before {
  top: -1px;
  left: -1px;
  border-top: 2px solid var(--accent);
  border-left: 2px solid var(--accent);
}
.marks::after {
  right: -1px;
  bottom: -1px;
  border-right: 2px solid var(--accent);
  border-bottom: 2px solid var(--accent);
}
.marks--on::before,
.marks--on::after,
.marks:hover::before,
.marks:hover::after,
.marks:focus-within::before,
.marks:focus-within::after {
  opacity: 1;
}

/* The hero is a dark surface that does NOT carry .band--ink, so every override for
   dark surfaces has to name both — otherwise dark-on-dark text goes invisible. */

/* -------------------------------------------------------------------------
   5. Header + navigation (always on ink, so it stays legible over any band)
   ------------------------------------------------------------------------- */
.masthead {
  position: sticky;
  top: 0;
  z-index: 40;
  background: var(--ink);
  color: var(--on-ink);
  border-bottom: 1px solid var(--rule-ink);
}

.masthead__bar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  min-height: var(--header-h);
}

.wordmark {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 1.25rem;
  letter-spacing: 0.02em;
  text-transform: uppercase;
  color: #fff;
  text-decoration: none;
  white-space: nowrap;
  display: inline-flex;
  align-items: baseline;
  gap: 0.4em;
  /* Padding rather than min-height: keeps the mark on one line while still
     clearing the 44px tap target, so the sticky header stays shallow on phones. */
  padding-block: 11px;
}
.masthead .wordmark:hover {
  color: #fff;
}
.wordmark__x {
  color: var(--accent);
}
.wordmark__sub {
  font-size: 0.62em;
  letter-spacing: 0.26em;
  color: var(--on-ink-dim);
  font-weight: 600;
}

.navwrap {
  display: flex;
  align-items: center;
  gap: 10px;
}

.nav-drop > summary {
  list-style: none;
  cursor: pointer;
  font-family: var(--font-display);
  font-size: 0.8125rem;
  font-weight: 600;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--on-ink);
  padding: 11px 14px;
  border: 1px solid var(--rule-ink);
  display: inline-flex;
  align-items: center;
  gap: 9px;
  min-height: 44px;
}
.nav-drop > summary::-webkit-details-marker {
  display: none;
}
/* Three bars. A plain linear-gradient fills the whole box, so `repeat-y` did nothing
   and only the first bar was drawn — this has to be a repeating gradient. The 4px
   period against a 10px box yields bars at 0–2, 4–6 and 8–10. */
.nav-drop > summary::after {
  content: "";
  width: 16px;
  height: 10px;
  flex: none;
  background-image: repeating-linear-gradient(
    to bottom,
    currentColor 0 2px,
    transparent 2px 4px
  );
}
.nav-drop[open] > summary {
  border-color: var(--accent);
  color: var(--accent);
}

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

/* Do not rely on the UA hiding a closed <details>' content: browsers now do that with
   content-visibility on ::details-content rather than display:none. Control both states
   explicitly instead — and note that setting `display` on .nav-panel is only half of it,
   because the hiding happens on the pseudo-element that WRAPS the panel, not on the panel.
   The desktop rule below has to reach ::details-content itself; see the note there.
   The masthead is position:sticky, so it is the containing block for the open panel. */
.nav-drop > .nav-panel {
  display: none;
}
.nav-drop[open] > .nav-panel {
  display: block;
  position: absolute;
  left: 0;
  right: 0;
  top: 100%;
  background: var(--ink);
  border-top: 1px solid var(--rule-ink);
  border-bottom: 1px solid var(--rule-ink);
  padding: 6px var(--gutter) 18px;
  max-height: calc(100vh - var(--header-h));
  overflow-y: auto;
}

.nav-list a {
  display: block;
  padding: 13px 0;
  border-bottom: 1px solid var(--rule-ink);
  font-family: var(--font-display);
  font-size: 0.9375rem;
  font-weight: 600;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  text-decoration: none;
  color: var(--on-ink);
}
.nav-list a:hover,
.nav-list a[aria-current] {
  color: var(--accent);
}

.langswitch {
  display: inline-flex;
  border: 1px solid var(--rule-ink);
}
.langswitch a {
  font-family: var(--font-display);
  font-size: 0.75rem;
  font-weight: 700;
  letter-spacing: 0.12em;
  text-decoration: none;
  color: var(--on-ink-dim);
  padding: 10px 11px;
  min-width: 44px;
  min-height: 44px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
}
.langswitch a[aria-current="true"] {
  background: var(--accent);
  color: var(--ink);
}

/* The full bar needs room for nine links plus the language switch, measured against the
   German labels, which are the long ones. The row needs 741px and the bar needs 1125px of
   viewport to hold it beside the wordmark and the language switch, so the drawer hands over
   at 1160 rather than the 1040 this used to use — below that it holds any number of items.

   The items also carry `flex: none`. Without it the row silently shrinks each link by a few
   pixels instead of overflowing, which ate the trailing letter-spacing and would have begun
   cutting glyphs as soon as a label grew. Better that a link fails to fit visibly than that
   every label quietly loses its last millimetre. */
@media (min-width: 1160px) {
  .nav-drop > summary {
    display: none;
  }
  /* Full nav is always visible here, open or not, and drops the drawer styling.

     `display: block` on the panel is not enough on its own. In a browser that implements
     ::details-content (Chrome 131+), a closed <details> puts content-visibility: hidden on
     that pseudo-element, which wraps the panel — so the panel was display:block inside a
     subtree the browser did not render, and the whole nav measured 0 wide and painted
     nothing. On a 1440px production page that left eight links invisible with the MENU
     button already hidden by this media query: no navigation at all above the breakpoint.
     Overriding the pseudo is what actually restores it. Browsers without the pseudo ignore
     this rule as an unknown selector and are served by the display rule, which is the
     behaviour they still implement. */
  .nav-drop::details-content {
    content-visibility: visible;
    block-size: auto;
  }
  .nav-drop > .nav-panel,
  .nav-drop[open] > .nav-panel {
    display: block;
    position: static;
    background: none;
    border: 0;
    padding: 0;
    max-height: none;
    overflow: visible;
  }
  .nav-list {
    display: flex;
    align-items: center;
    gap: clamp(14px, 1.6vw, 26px);
  }
  .nav-list > li {
    flex: none;
  }
  .nav-list a {
    padding: 6px 0;
    border-bottom: 1px solid transparent;
    font-size: 0.8125rem;
    letter-spacing: 0.14em;
  }
  .nav-list a:hover,
  .nav-list a[aria-current] {
    border-bottom-color: var(--accent);
  }
  .wordmark {
    font-size: 1.4rem;
  }
}

/* -------------------------------------------------------------------------
   6. Hero
   ------------------------------------------------------------------------- */
.hero {
  position: relative;
  overflow: hidden;
  background: var(--ink);
  color: var(--on-ink);
  padding-block: clamp(52px, 10vw, 116px) clamp(40px, 7vw, 84px);
}

/* Faint 12-column blueprint overlay, faded out toward the bottom. */
.hero__grid {
  position: absolute;
  inset: 0;
  pointer-events: none;
  background-image: repeating-linear-gradient(
    to right,
    var(--rule-ink) 0 1px,
    transparent 1px calc(100% / 6)
  );
  -webkit-mask-image: linear-gradient(
    to bottom,
    rgba(0, 0, 0, 0.85),
    transparent 80%
  );
  mask-image: linear-gradient(to bottom, rgba(0, 0, 0, 0.85), transparent 80%);
}

.hero__inner {
  position: relative;
}

.kicker {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 10px 14px;
  font-family: var(--font-display);
  font-size: clamp(0.6875rem, 0.62rem + 0.3vw, 0.8125rem);
  font-weight: 600;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--accent);
  margin-bottom: clamp(24px, 4vw, 44px);
}
.kicker__dot {
  color: var(--on-ink-dim);
}

.hero__mark {
  font-family: var(--font-display);
  font-weight: 700;
  text-transform: uppercase;
  line-height: 0.86;
  letter-spacing: -0.015em;
  font-size: clamp(3.25rem, 15vw, 9.5rem);
  color: #fff;
  margin: 0;
}
.hero__mark .wordmark__x {
  color: var(--accent);
}

/* Optical alignment. The three lines of the H1 sit in layout boxes that all start at the
   same x, but a glyph's ink starts inside its box by the font's left side bearing, and that
   bearing scales with font size: 0.06em on Oswald's "L" is 3.4px at the mobile hero size and
   ~9px at the desktop one, against 0.6px for the small caps below it. Left uncorrected,
   LUXGRID reads as indented. Each line is pulled back by its own bearing, expressed in its
   own em so the correction tracks the fluid type scale. */
.hero__brand {
  display: block;
  margin-left: -0.06em;
}
.hero__sub {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 10px 16px;
  margin-top: clamp(10px, 1.6vw, 18px);
}
.hero__sub-word {
  margin-left: -0.041em;
  font-family: var(--font-display);
  font-size: clamp(0.875rem, 0.8rem + 0.7vw, 1.375rem);
  font-weight: 600;
  letter-spacing: clamp(0.2em, 0.5vw, 0.44em);
  text-transform: uppercase;
  color: var(--on-ink);
  white-space: nowrap;
}
.hero__rule {
  flex: 0 0 clamp(24px, 6vw, 96px);
  height: 1px;
  background: var(--rule-ink);
}
.hero__claim {
  margin-left: -0.063em;
  font-family: var(--font-display);
  font-size: clamp(0.8125rem, 0.74rem + 0.45vw, 1.0625rem);
  font-weight: 600;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--accent);
  line-height: 1.3;
}

.hero__lead {
  max-width: 56ch;
  margin-top: clamp(26px, 4vw, 42px);
  font-size: clamp(1.0625rem, 1rem + 0.4vw, 1.3125rem);
  line-height: 1.6;
  color: var(--on-ink-dim);
}

.cta-row {
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
  margin-top: clamp(26px, 4vw, 40px);
}

/* -------------------------------------------------------------------------
   7. Buttons
   ------------------------------------------------------------------------- */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
  min-height: 50px;
  padding: 13px 26px;
  font-family: var(--font-display);
  font-size: 0.875rem;
  font-weight: 700;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  text-decoration: none;
  border: 1px solid transparent;
  transition: background 0.16s ease, color 0.16s ease, border-color 0.16s ease;
}

.btn--solid {
  background: var(--accent);
  color: var(--ink);
}
.btn--solid:hover {
  background: var(--accent-bright);
  color: var(--ink);
}

.btn--ghost {
  border-color: currentColor;
  color: inherit;
  background: transparent;
}
:is(.band--ink, .hero) .btn--ghost:hover {
  border-color: var(--accent);
  color: var(--accent);
}
.band--paper .btn--ghost:hover {
  background: var(--on-paper);
  color: var(--paper);
  border-color: var(--on-paper);
}

/* -------------------------------------------------------------------------
   8. Section heads — index number sitting on a rule, label, title
   ------------------------------------------------------------------------- */
.shead {
  margin-bottom: clamp(32px, 5vw, 60px);
}

.shead__top {
  display: flex;
  align-items: center;
  gap: 14px;
  margin-bottom: 18px;
}
.shead__idx {
  font-family: var(--font-display);
  font-size: 0.8125rem;
  font-weight: 700;
  letter-spacing: 0.12em;
  color: var(--accent-deep);
  font-variant-numeric: tabular-nums;
}
:is(.band--ink, .hero) .shead__idx {
  color: var(--accent);
}
.shead__label {
  font-family: var(--font-display);
  font-size: 0.75rem;
  font-weight: 600;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--on-paper-dim);
  white-space: nowrap;
}
:is(.band--ink, .hero) .shead__label {
  color: var(--on-ink-dim);
}
.shead__top::after {
  content: "";
  flex: 1;
  height: 1px;
  background: var(--rule-paper);
}
:is(.band--ink, .hero) .shead__top::after {
  background: var(--rule-ink);
}

.shead__title {
  font-size: clamp(1.875rem, 1.4rem + 2.6vw, 3.5rem);
  max-width: 22ch;
}
.shead__lead {
  margin-top: 18px;
  max-width: 60ch;
  color: var(--on-paper-dim);
  font-size: clamp(1rem, 0.97rem + 0.2vw, 1.125rem);
}
:is(.band--ink, .hero) .shead__lead {
  color: var(--on-ink-dim);
}

/* -------------------------------------------------------------------------
   9. Service cards (home + related)
   ------------------------------------------------------------------------- */
.svc-grid {
  display: grid;
  gap: 1px;
  grid-template-columns: 1fr;
}

.svc {
  position: relative;
  background: var(--paper);
  box-shadow: 0 0 0 1px var(--rule-paper);
  padding: clamp(22px, 3vw, 34px);
  text-decoration: none;
  color: inherit;
  display: flex;
  flex-direction: column;
  gap: 12px;
  transition: background 0.16s ease;
}
.svc:hover {
  background: var(--paper-raised);
  color: inherit;
}

.svc__idx {
  font-family: var(--font-display);
  font-size: 0.75rem;
  font-weight: 700;
  letter-spacing: 0.14em;
  color: var(--accent-deep);
  font-variant-numeric: tabular-nums;
}
/* Drawn icons take their colour from the surface they sit on, so one definition
   serves both the light cards and the dark hero. */
.ico {
  display: block;
}
.svc__icon {
  display: block;
  color: var(--accent-deep);
  margin-bottom: 2px;
}
.svc:hover .svc__icon {
  color: var(--on-paper);
}

/* Live parts of the service icons (partials/icons.njk). Lit is the resting state, as with the
   diagrams: the unlit start exists only on cards that animate them, inside the motion query.
   Cards get data-diagram only on pages that load diagrams.js; without the script they would
   wait unlit forever. */
.ico-lit {
  fill: var(--accent);
  fill-opacity: 0.55;
}
.ico-cell {
  stroke: none;
}
.ico-d1 {
  --ico-at: 0.1s;
}
.ico-d2 {
  --ico-at: 0.3s;
}
.ico-d3 {
  --ico-at: 0.5s;
}
.ico-d4 {
  --ico-at: 0.7s;
}
@media (scripting: enabled) and (prefers-reduced-motion: no-preference) {
  /* Butt caps: a square cap paints a dot at the start of a stroke that has not drawn yet. */
  .svc__icon[data-diagram] .ico-draw {
    stroke-dasharray: 1;
    stroke-linecap: butt;
  }
  .svc__icon[data-diagram]:not(.is-live) .ico-lit {
    fill-opacity: 0;
  }
  .svc__icon[data-diagram]:not(.is-live) .ico-bar {
    opacity: 0;
  }
  .svc__icon[data-diagram]:not(.is-live) .ico-draw {
    stroke-dashoffset: 1;
  }
  .svc__icon.is-live .ico-lit {
    animation: ico-lit 0.35s ease calc(var(--ico-at) + var(--ico-offset, 0s)) both;
  }
  .svc__icon.is-live .ico-bar {
    animation: ico-bar 0.25s ease calc(var(--ico-at) + var(--ico-offset, 0s)) both;
  }
  .svc__icon.is-live .ico-draw {
    animation: ico-draw 0.45s cubic-bezier(0.45, 0, 0.25, 1) calc(var(--ico-at) + var(--ico-offset, 0s)) both;
  }
}
/* On a grid of two or three columns, cards in view together light up one after another. */
@media (min-width: 620px) {
  .svc-grid > .svc:nth-child(2) .svc__icon {
    --ico-offset: 0.12s;
  }
  .svc-grid > .svc:nth-child(3) .svc__icon {
    --ico-offset: 0.24s;
  }
  .svc-grid > .svc:nth-child(4) .svc__icon {
    --ico-offset: 0.36s;
  }
  .svc-grid > .svc:nth-child(5) .svc__icon {
    --ico-offset: 0.48s;
  }
  .svc-grid > .svc:nth-child(6) .svc__icon {
    --ico-offset: 0.6s;
  }
}
@keyframes ico-lit {
  0% { fill-opacity: 0; }
  100% { fill-opacity: 0.55; }
}
@keyframes ico-bar {
  0% { opacity: 0; }
  100% { opacity: 1; }
}
@keyframes ico-draw {
  0% { stroke-dashoffset: 1; }
  100% { stroke-dashoffset: 0; }
}
.svc__name {
  font-size: clamp(1.125rem, 1rem + 0.5vw, 1.4375rem);
}
.svc__teaser {
  margin: 0;
  color: var(--on-paper-dim);
  font-size: 0.9375rem;
  line-height: 1.6;
}
.svc__go {
  margin-top: auto;
  font-family: var(--font-display);
  font-size: 0.75rem;
  font-weight: 700;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--accent-deep);
  display: inline-flex;
  align-items: center;
  gap: 8px;
}
.svc:hover .svc__go {
  gap: 14px;
}

@media (min-width: 620px) {
  .svc-grid {
    grid-template-columns: repeat(2, 1fr);
  }
}
@media (min-width: 1000px) {
  .svc-grid {
    grid-template-columns: repeat(3, 1fr);
  }
}

/* -------------------------------------------------------------------------
   10. Service page body
   ------------------------------------------------------------------------- */
.crumbs {
  font-family: var(--font-display);
  font-size: 0.75rem;
  font-weight: 600;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--on-ink-dim);
  margin-bottom: clamp(22px, 3.5vw, 36px);
}
.crumbs ol {
  list-style: none;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 10px;
  margin: 0;
  padding: 0;
}
.crumbs a {
  text-decoration: none;
}
.crumbs li + li::before {
  content: "/";
  margin-right: 10px;
  color: var(--rule-ink);
}

.svc-hero__title {
  font-size: clamp(2.25rem, 1.5rem + 5vw, 5rem);
  max-width: 20ch;
}
.svc-hero__promise {
  margin-top: clamp(20px, 3vw, 30px);
  max-width: 46ch;
  font-size: clamp(1.0625rem, 1rem + 0.45vw, 1.375rem);
  line-height: 1.55;
  color: var(--accent);
  font-weight: 600;
}
.svc-hero__icon {
  display: block;
  color: var(--accent);
  margin-bottom: 26px;
}

.prose {
  max-width: 68ch;
}
.prose p {
  margin: 0 0 1.15em;
  font-size: clamp(1.0625rem, 1rem + 0.25vw, 1.1875rem);
  line-height: 1.7;
}
.prose p:last-child {
  margin-bottom: 0;
}

/* Two-column split: label rail on the left, content on the right. */
.split {
  display: grid;
  gap: clamp(20px, 3vw, 30px);
  padding-block: clamp(34px, 5vw, 62px);
  border-top: 1px solid var(--rule-paper);
}
.split:first-of-type {
  border-top: 0;
  padding-top: 0;
}
.split__label {
  font-family: var(--font-display);
  font-size: 0.75rem;
  font-weight: 600;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--on-paper-dim);
}
@media (min-width: 900px) {
  .split {
    grid-template-columns: minmax(140px, 2fr) 9fr;
    gap: clamp(24px, 4vw, 56px);
  }
}

/* Numbered process steps with a schematic connector line. */
.steps {
  list-style: none;
  margin: 0;
  padding: 0;
  counter-reset: step;
}
.step {
  counter-increment: step;
  position: relative;
  padding: 0 0 26px 46px;
}
.step::before {
  content: "0" counter(step);
  position: absolute;
  left: 0;
  top: 0;
  font-family: var(--font-display);
  font-size: 0.8125rem;
  font-weight: 700;
  letter-spacing: 0.08em;
  color: var(--accent-deep);
  font-variant-numeric: tabular-nums;
}
.step::after {
  content: "";
  position: absolute;
  left: 12px;
  top: 22px;
  bottom: 4px;
  width: 1px;
  background: var(--rule-paper);
}
.step:last-child {
  padding-bottom: 0;
}
.step:last-child::after {
  display: none;
}
.step__title {
  font-size: 1.0625rem;
  margin-bottom: 5px;
}
.step__desc {
  margin: 0;
  color: var(--on-paper-dim);
  font-size: 0.9375rem;
  line-height: 1.6;
}

/* Spec table */
.specs {
  margin: 0;
  border-top: 1px solid var(--rule-paper);
}
.spec {
  display: grid;
  gap: 2px 20px;
  padding: 14px 0;
  border-bottom: 1px solid var(--rule-paper);
}
.spec__k {
  font-family: var(--font-display);
  font-size: 0.75rem;
  font-weight: 600;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--on-paper-dim);
}
.spec__v {
  margin: 0;
  font-size: 0.9375rem;
}
@media (min-width: 620px) {
  .spec {
    grid-template-columns: minmax(150px, 1fr) 2fr;
    align-items: baseline;
  }
}

/* Audience tiles. Five of them never fill a three-column row evenly, which is why the
   hairlines are drawn per cell above rather than by the container background. */
.who {
  display: grid;
  gap: 1px;
  grid-template-columns: 1fr;
  list-style: none;
  margin: 0;
  padding: 0;
}
.who__item {
  --who-pad: clamp(22px, 3vw, 32px);
  position: relative;
  background: var(--paper);
  box-shadow: 0 0 0 1px var(--rule-paper);
  padding: var(--who-pad);
}
/* The drawing bleeds to the tile's sides so the ground lines of neighbouring tiles meet. */
.dg.who__art {
  max-width: none;
  margin: 0 calc(-1 * var(--who-pad)) 18px;
  overflow: hidden;
}
/* Wider tiles would leave the building small in empty ground: enlarge it and crop the
   sides, which only ever hold ground line. */
@media (min-width: 620px) {
  .who__art .dg__svg {
    width: 130%;
    margin-left: -15%;
  }
}
.who__title {
  font-size: clamp(1.0625rem, 0.98rem + 0.4vw, 1.3125rem);
  margin-bottom: 10px;
  color: var(--accent-deep);
}
.who__desc {
  margin: 0;
  color: var(--on-paper-dim);
  font-size: 0.9375rem;
  line-height: 1.6;
}
@media (min-width: 620px) {
  .who {
    grid-template-columns: repeat(2, 1fr);
  }
  .who__item:nth-child(2n) {
    --dg-offset: 0.35s;
  }
}
@media (min-width: 1000px) {
  .who {
    grid-template-columns: repeat(3, 1fr);
  }
  .who__item:nth-child(n) {
    --dg-offset: 0s;
  }
  .who__item:nth-child(3n + 2) {
    --dg-offset: 0.35s;
  }
  .who__item:nth-child(3n) {
    --dg-offset: 0.7s;
  }
}

/* Audience pills */
.pills {
  display: flex;
  flex-wrap: wrap;
  gap: 9px;
  list-style: none;
  margin: 0;
  padding: 0;
}
.pill {
  border: 1px solid var(--rule-paper);
  padding: 8px 15px;
  font-family: var(--font-display);
  font-size: 0.8125rem;
  font-weight: 600;
  letter-spacing: 0.1em;
  text-transform: uppercase;
}
:is(.band--ink, .hero) .pill {
  border-color: var(--rule-ink);
}

/* FAQ disclosures.

   Hiding the answer is left entirely to the UA. That is deliberate: the browser does it with
   content-visibility: hidden on ::details-content (verified in Chrome 152), and unlike
   display:none that state is reversible by the browser itself — which is what lets
   find-in-page open the matching answer. A collapsed answer is out of the accessibility tree
   either way, as a disclosure should be; the difference is only whether the browser can
   reveal it. .nav-panel has to override the UA because a closed <details> there must still
   lay out. Nothing here may: no display, visibility or content-visibility on .faq__a. */
.faq {
  border-top: 1px solid var(--rule-paper);
  max-width: 82ch;
}
.faq__item {
  border-bottom: 1px solid var(--rule-paper);
}

.faq__q {
  display: flex;
  align-items: flex-start;
  gap: 16px;
  padding: 17px 0;
  cursor: pointer;
  /* Both are needed to drop the UA triangle: list-style for Firefox and Chrome's
     ::marker, the pseudo-element for older Safari. */
  list-style: none;
}
.faq__q::-webkit-details-marker {
  display: none;
}

/* Questions are full sentences, so they break the site's display-font heading rule: 40
   characters of condensed uppercase Oswald is a headline, not a question someone scans. */
.faq__q h3 {
  flex: 1;
  font-family: var(--font-body);
  font-size: 1.0625rem;
  font-weight: 600;
  line-height: 1.45;
  letter-spacing: 0;
  text-transform: none;
}
@media (hover: hover) {
  .faq__q:hover h3 {
    color: var(--accent-deep);
  }
}

/* A drawn plus that loses its upright when open — hairline weight, like the grid lines,
   rather than a rotating glyph. */
.faq__q::after {
  content: "";
  flex: none;
  width: 13px;
  height: 13px;
  margin-top: 6px;
  background:
    linear-gradient(var(--accent-deep) 0 0) center / 100% 1px no-repeat,
    linear-gradient(var(--accent-deep) 0 0) center / 1px 100% no-repeat;
}
.faq__item[open] .faq__q::after {
  background: linear-gradient(var(--accent-deep) 0 0) center / 100% 1px no-repeat;
}

/* 29px right padding = the 13px marker plus the 16px gap, so the answer ends on the same
   line as the question text above it rather than running under the marker. */
.faq__a {
  padding: 0 29px 22px 0;
  max-width: 72ch;
}
.faq__a p {
  margin: 0;
  color: var(--on-paper-dim);
  font-size: 0.9375rem;
  line-height: 1.7;
}
/* Link to the article that answers this question at length. `.faq__a p` above is one class
   plus one element, so the override needs to match that weight rather than reach for
   !important. The few that exist here are all motion overrides that must beat any later
   rule (reduced-motion, the pause button); layout is not one of those cases. */
.faq__a .faq__more {
  margin-top: 12px;
}
.faq__more a,
.projgrid-more a {
  font-family: var(--font-display);
  font-size: 0.75rem;
  font-weight: 600;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

/* -------------------------------------------------------------------------
   11. Photos
   ------------------------------------------------------------------------- */
.shots {
  display: grid;
  gap: clamp(14px, 2vw, 22px);
  grid-template-columns: 1fr;
  align-items: start;
}
@media (min-width: 640px) {
  .shots {
    grid-template-columns: repeat(2, 1fr);
  }
}
@media (min-width: 1000px) {
  .shots--3 {
    grid-template-columns: repeat(3, 1fr);
  }
}

.shot {
  margin: 0;
  position: relative;
}
/* No forced aspect ratio: the set mixes portrait shots of inverters and switchboards with
   landscape shots of roofs and carports, and cropping everything to 4:3 sliced the tall ones
   through the middle. Each photo keeps its own proportions; the width/height attributes in
   the markup still reserve the space, so nothing shifts while loading. */
.shot img {
  width: 100%;
  height: auto;
  background: var(--paper-raised);
}
.shot figcaption {
  margin-top: 10px;
  font-size: 0.8125rem;
  line-height: 1.5;
  color: var(--on-paper-dim);
  padding-left: 13px;
  border-left: 2px solid var(--accent);
}

/* -------------------------------------------------------------------------
   Award badge
   ------------------------------------------------------------------------- */
.award {
  padding-block: clamp(34px, 5vw, 56px);
  border-top: 1px solid var(--rule-paper);
}
.award__inner {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: clamp(20px, 3vw, 40px);
}
.award__tile {
  flex: none;
  display: block;
  line-height: 0;
  border: 1px solid var(--rule-paper);
  transition: border-color 0.16s ease;
}
.award__tile:hover {
  border-color: var(--accent-deep);
}
.award__tile img {
  width: auto;
  height: clamp(92px, 12vw, 124px);
}
.award__text {
  flex: 1 1 300px;
}
.award__title {
  font-size: clamp(1.25rem, 1.1rem + 0.7vw, 1.625rem);
  margin-bottom: 10px;
}
.award__body {
  margin: 0 0 8px;
  max-width: 58ch;
  color: var(--on-paper-dim);
  font-size: 0.9375rem;
  line-height: 1.6;
}
.award__meta {
  margin: 0;
  font-size: 0.8125rem;
  color: var(--on-paper-dim);
}

/* -------------------------------------------------------------------------
   Blog: index list and post body
   ------------------------------------------------------------------------- */

/* Post hero. The title is a full sentence, often a question, so like the FAQ questions it
   leaves the display face to the section headings and stays in the body face — condensed
   uppercase Oswald over three lines reads as a poster, not as something to start reading. */
.post__title {
  font-family: var(--font-body);
  font-weight: 700;
  font-size: clamp(1.625rem, 1.25rem + 1.9vw, 2.75rem);
  line-height: 1.18;
  letter-spacing: -0.015em;
  text-transform: none;
  max-width: 24ch;
}
.post__lead {
  margin: 18px 0 0;
  max-width: 56ch;
  color: var(--on-ink-dim);
  font-size: clamp(1.0625rem, 1rem + 0.3vw, 1.25rem);
  line-height: 1.55;
}
.post__meta {
  margin: 26px 0 0;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 10px;
  font-family: var(--font-display);
  font-size: 0.75rem;
  font-weight: 600;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--on-ink-dim);
}

/* Post body. The markdown sets h2 and the prose is the only thing on the band, so the
   measure is set here rather than on a wrapper. */
.post {
  max-width: 68ch;
}
.post > :first-child {
  margin-top: 0;
}
.post p {
  margin: 0 0 1.15em;
  font-size: clamp(1.0625rem, 1rem + 0.25vw, 1.1875rem);
  line-height: 1.7;
}
.post h2 {
  font-size: clamp(1.25rem, 1.05rem + 0.9vw, 1.75rem);
  margin: 1.9em 0 0.6em;
  padding-top: 0.85em;
  border-top: 1px solid var(--rule-paper);
}
.post h2:first-child {
  margin-top: 0;
  padding-top: 0;
  border-top: 0;
}
.post ul {
  margin: 0 0 1.3em;
  padding-left: 0;
  list-style: none;
}
.post ul li {
  position: relative;
  padding-left: 22px;
  margin-bottom: 0.5em;
  line-height: 1.65;
}
/* A hairline dash for the bullet, the same weight as the section rules. */
.post ul li::before {
  content: "";
  position: absolute;
  left: 0;
  top: 0.72em;
  width: 11px;
  height: 1px;
  background: var(--accent-deep);
}
.post strong {
  font-weight: 700;
}

/* Index list, also reused under a post for "more posts". */
.postlist {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: clamp(14px, 2vw, 20px);
}
@media (min-width: 900px) {
  .postlist--compact {
    grid-template-columns: repeat(3, 1fr);
  }
}

.postcard {
  position: relative;
  border: 1px solid var(--rule-paper);
  background: var(--paper);
}
.postcard > a {
  display: block;
  padding: clamp(20px, 3vw, 30px);
  text-decoration: none;
  color: inherit;
  height: 100%;
}
.postcard:hover {
  border-color: var(--accent-deep);
}
.postcard__date {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px;
  font-family: var(--font-display);
  font-size: 0.6875rem;
  font-weight: 600;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--on-paper-dim);
}
.postcard__svc {
  color: var(--accent-deep);
}
.postcard__title {
  font-family: var(--font-body);
  font-weight: 700;
  font-size: clamp(1.0625rem, 1rem + 0.45vw, 1.375rem);
  line-height: 1.3;
  letter-spacing: -0.01em;
  text-transform: none;
  margin: 12px 0 0;
  max-width: 44ch;
}
.postcard__lead {
  margin: 10px 0 0;
  max-width: 68ch;
  color: var(--on-paper-dim);
  font-size: 0.9375rem;
  line-height: 1.6;
}
.postcard .svc__go {
  margin-top: 16px;
}
.postcard:hover .svc__go {
  transform: translateX(4px);
}

/* One service card under a post: it is the call to action, so it does not stretch to the
   grid width the six-up related list uses. */
@media (min-width: 620px) {
  .svc-grid--one {
    grid-template-columns: minmax(0, 420px);
  }
}

/* Legal pages */
.legal {
  max-width: 72ch;
}
.legal__h {
  font-size: clamp(1.125rem, 1rem + 0.6vw, 1.5rem);
  margin: 2em 0 0.7em;
  padding-top: 0.8em;
  border-top: 1px solid var(--rule-paper);
}
.legal__h:first-child {
  margin-top: 0;
  padding-top: 0;
  border-top: 0;
}
.legal__list {
  margin: 0 0 1.2em;
  padding-left: 1.1em;
}
.legal__list li {
  margin-bottom: 0.5em;
  line-height: 1.65;
}
.legal code {
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 0.9em;
  background: var(--paper-raised);
  padding: 1px 5px;
}
/* A company detail the owner still has to supply. Loud on purpose. */
.todo {
  background: #ffe8a3;
  color: #4a3400;
  font-weight: 700;
  padding: 1px 6px;
  box-decoration-break: clone;
  -webkit-box-decoration-break: clone;
}

.note {
  border-left: 2px solid var(--accent);
  padding-left: 16px;
  color: var(--on-paper-dim);
  max-width: 56ch;
  margin: 0;
}

/* Project cards (home 00.2, portfolio 07.1, service pages, under a project). One column on a
   phone, two from 620px, four from 1000px — the home page's four fill one row. */
.projgrid {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: clamp(14px, 2vw, 20px);
  grid-template-columns: 1fr;
}
/* Home only: four stacked cards would make the teaser longer than the section it leads to, so
   on a phone they become a row to swipe, the next card peeking in. It never moves by itself.
   A scroll container clips at its padding box, and the focus ring sits 5px outside the card
   (2px outline, 3px offset): the padding makes room for it, and the negative margin, taken
   from the rail's gutter, keeps the cards aligned with the heading above. */
.projgrid--strip {
  display: flex;
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  scroll-padding-inline: 6px;
  padding: 6px 6px 14px;
  margin: -6px -6px 0;
}
.projgrid--strip > .proj {
  flex: 0 0 min(82%, 340px);
  scroll-snap-align: start;
}
.projgrid--strip::-webkit-scrollbar {
  height: 8px;
}
.projgrid--strip::-webkit-scrollbar-thumb {
  background: var(--rule-paper);
  border-radius: 4px;
}
@media (min-width: 620px) {
  .projgrid,
  .projgrid--strip {
    display: grid;
    grid-template-columns: repeat(2, 1fr);
    overflow: visible;
    padding: 0;
    margin: 0;
  }
}
@media (min-width: 1000px) {
  .projgrid,
  .projgrid--strip {
    grid-template-columns: repeat(4, 1fr);
  }
}
/* On a service page the cards come first and the loose photos follow under them. */
.projgrid + .shots,
.projgrid + .note,
.projgrid-more + .shots,
.projgrid-more + .note {
  margin-top: clamp(28px, 4vw, 44px);
}
/* "All projects" under a service page's four. */
.projgrid-more {
  margin: 18px 0 0;
}

.proj {
  position: relative;
  border: 1px solid var(--rule-paper);
  background: var(--paper);
}
.proj:hover {
  border-color: var(--accent-deep);
}
/* On a phone a card is a list row, thumbnail left: at 375px the portfolio's twelve projects
   measured 4,711px as stacked cards and 1,397px as rows. The image keeps its 4:3 box for
   sizing, then stretches to the row's height and crops (object-fit) if the title runs long.
   The home page's swipeable row and every layout from 620px use the stacked card instead,
   image on top — the overrides below. */
.proj > a {
  display: grid;
  grid-template-columns: minmax(0, 38%) minmax(0, 1fr);
  height: 100%;
  text-decoration: none;
  color: inherit;
}
.proj__img {
  display: block;
  width: 100%;
  height: 100%;
  aspect-ratio: 4 / 3;
  object-fit: cover;
  background: var(--paper-raised);
}
.proj__body {
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: 4px;
  padding: 12px 14px;
}
.proj__place {
  font-family: var(--font-display);
  font-size: 0.6875rem;
  font-weight: 600;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--accent-deep);
}
/* A full phrase, not a label: body face, like the post titles. */
.proj__title {
  margin: 0;
  font-family: var(--font-body);
  font-weight: 700;
  font-size: clamp(1rem, 0.95rem + 0.3vw, 1.1875rem);
  line-height: 1.3;
  letter-spacing: -0.01em;
  text-transform: none;
}
.proj .svc__go {
  display: none;
  margin-top: auto;
  padding-top: 6px;
}
/* The stacked card. Same declarations twice: the home row at every width, and every card
   from 620px — min-width queries only, so they cannot share one rule. */
.projgrid--strip .proj > a {
  display: flex;
  flex-direction: column;
}
.projgrid--strip .proj__img {
  height: auto;
}
.projgrid--strip .proj__body {
  flex: 1;
  justify-content: flex-start;
  gap: 8px;
  padding: 16px;
}
.projgrid--strip .proj .svc__go {
  display: inline-flex;
}
@media (min-width: 620px) {
  .proj > a {
    display: flex;
    flex-direction: column;
  }
  .proj__img {
    height: auto;
  }
  .proj__body,
  .projgrid--strip .proj__body {
    flex: 1;
    justify-content: flex-start;
    gap: 8px;
    padding: clamp(16px, 2vw, 22px);
  }
  .proj .svc__go {
    display: inline-flex;
  }
}
.proj:hover .svc__go {
  transform: translateX(4px);
}

/* -------------------------------------------------------------------------
   12. Trust cards
   ------------------------------------------------------------------------- */
.trust {
  display: grid;
  gap: 1px;
  grid-template-columns: 1fr;
}
.trust__item {
  background: var(--paper);
  box-shadow: 0 0 0 1px var(--rule-paper);
  padding: clamp(22px, 3vw, 32px);
}
.trust__title {
  font-size: 1.1875rem;
  margin-bottom: 9px;
}
.trust__desc {
  margin: 0;
  color: var(--on-paper-dim);
  font-size: 0.9375rem;
  line-height: 1.6;
}
@media (min-width: 760px) {
  .trust {
    grid-template-columns: repeat(3, 1fr);
  }
}

/* Experience figures (home 00.6). Same hairline grid as the trust cards above.

   Only .stat__final sizes the figure. The moving .stat__tick is laid over it, anchored to the
   right edge, so its digits grow leftwards and the "+" never moves. It must stay out of the
   layout: Oswald's figures are proportional, and tabular-nums does nothing with the files we
   ship — measured, "1111" is 61.6px and "0000" 88px at the same size, with or without it. A
   shared grid cell, the first version, let the wider "0" stretch the figure while counting,
   and the "+" jumped about 4px when "7" settled.

   While counting, the final number is hidden with opacity, never visibility — visibility would
   take it out of the accessibility tree, and a screen reader would then find no number at all.
   Labels hyphenate on phones: German compounds like "Mehrfamilienhausprojekten" are wider than
   a two-column phone cell. */
.stats {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: 1px;
  grid-template-columns: repeat(2, minmax(0, 1fr));
}
.stat {
  background: var(--paper);
  box-shadow: 0 0 0 1px var(--rule-paper);
  padding: clamp(18px, 3vw, 32px);
}
.stat__fig {
  display: block;
  font-family: var(--font-display);
  font-weight: 700;
  font-size: clamp(2.5rem, 1.7rem + 3.4vw, 4.5rem);
  line-height: 1;
  letter-spacing: -0.01em;
}
.stat__num {
  position: relative;
  display: inline-block;
}
.stat__tick {
  position: absolute;
  top: 0;
  right: 0;
  white-space: nowrap;
}
/* Generated content, so the moving digits are never part of the page's text. */
.stat__tick::before {
  content: attr(data-value);
}
.stat__num.is-counting .stat__final {
  opacity: 0;
}
/* Printed before the figures scrolled into view, an armed figure would read "0+". */
@media print {
  .stat__num.is-counting .stat__final {
    opacity: 1;
  }
  .stat__tick {
    display: none;
  }
}
.stat__plus {
  color: var(--accent-deep);
}
.stat__label {
  display: block;
  margin-top: 12px;
  max-width: 30ch;
  color: var(--on-paper-dim);
  font-size: 0.9375rem;
  line-height: 1.5;
  hyphens: auto;
  overflow-wrap: break-word;
}
@media (min-width: 760px) {
  .stats {
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }
  /* Three columns leave room for every label, so wrap at word boundaries. Hyphenation is for
     the two-column phone cell only; on desktop it split "kom-pleksową" for no reason. */
  .stat__label {
    hyphens: manual;
  }
}

/* -------------------------------------------------------------------------
   13. Contact band + footer
   ------------------------------------------------------------------------- */
.contact__title {
  font-size: clamp(1.875rem, 1.4rem + 2.6vw, 3.25rem);
  max-width: 24ch;
}
.contact__lead {
  margin-top: 18px;
  max-width: 54ch;
  color: var(--on-ink-dim);
}
.contact__meta {
  display: grid;
  gap: 1px;
  background: var(--rule-ink);
  border: 1px solid var(--rule-ink);
  margin-top: clamp(30px, 4vw, 48px);
  grid-template-columns: 1fr;
}
.contact__cell {
  background: var(--ink);
  padding: 18px clamp(16px, 2vw, 24px);
}
.contact__k {
  font-family: var(--font-display);
  font-size: 0.6875rem;
  font-weight: 600;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--on-ink-dim);
  margin-bottom: 6px;
}
.contact__v {
  margin: 0;
  font-size: 1rem;
  font-weight: 600;
  font-style: normal; /* the two addresses are <address>, which browsers set in italic */
}
/* Phone and e-mail are the conversion here, so they get a full tap target. */
.contact__v a {
  text-decoration: none;
  display: inline-flex;
  align-items: center;
  min-height: 44px;
}
@media (min-width: 720px) {
  .contact__meta {
    grid-template-columns: repeat(2, 1fr);
  }
}
@media (min-width: 1040px) {
  .contact__meta {
    grid-template-columns: repeat(4, 1fr);
  }
  .hero__inner--split .contact__meta {
    grid-template-columns: repeat(2, 1fr);
  }
}

/* Service area section on the home page: places beside the map. */
.area {
  display: grid;
  gap: clamp(34px, 6vw, 56px);
}
.area__groups {
  display: grid;
  gap: 1px;
  margin-top: clamp(26px, 4vw, 40px);
  background: var(--rule-ink);
  border: 1px solid var(--rule-ink);
}
.area__group {
  background: var(--ink);
  padding: 16px clamp(16px, 2vw, 22px);
}
.area__k {
  font-family: var(--font-display);
  font-size: 0.6875rem;
  font-weight: 600;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--on-ink-dim);
  margin: 0 0 6px;
}
.area__v {
  margin: 0;
  font-weight: 600;
  line-height: 1.6;
}
/* A place name never breaks across lines ("Kamień / Wielki"). */
.area__place {
  white-space: nowrap;
}
@media (min-width: 1000px) {
  .area {
    grid-template-columns: minmax(0, 1.08fr) minmax(0, 0.92fr);
    align-items: center;
  }
  .area__map .dg {
    margin-left: auto;
  }
}

/* Profiles elsewhere, under the contact details. Plain links: see partials/find-us.njk. */
.findus {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 4px 22px;
  margin-top: 16px;
}
.findus__k {
  font-family: var(--font-display);
  font-size: 0.6875rem;
  font-weight: 600;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--on-ink-dim);
}
.findus__list {
  display: flex;
  flex-wrap: wrap;
  gap: 0 22px;
  list-style: none;
  margin: 0;
  padding: 0;
}
.findus__link {
  display: inline-flex;
  align-items: center;
  gap: 9px;
  min-height: 44px;
  font-weight: 600;
  text-decoration: none;
}
.findus__link .ico {
  flex: none;
  color: var(--accent);
}

.foot {
  background: var(--ink);
  color: var(--on-ink-dim);
  border-top: 1px solid var(--rule-ink);
  padding-block: 30px;
  font-size: 0.8125rem;
}
.foot__rows {
  display: flex;
  flex-wrap: wrap;
  gap: 14px 26px;
  align-items: center;
  justify-content: space-between;
}
.foot__tag {
  font-family: var(--font-display);
  font-size: 0.75rem;
  font-weight: 600;
  letter-spacing: 0.16em;
  text-transform: uppercase;
}
.foot__links {
  display: flex;
  flex-wrap: wrap;
  gap: 0 20px;
  list-style: none;
  margin: 0;
  padding: 0;
}
.foot__links a,
.foot__links button {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
}
.foot button.linky {
  background: none;
  border: 0;
  padding: 0;
  font: inherit;
  color: var(--link);
  cursor: pointer;
  text-decoration: underline;
  text-underline-offset: 3px;
}

/* -------------------------------------------------------------------------
   14. Sticky call bar (phones only — the main conversion for a trade)
   ------------------------------------------------------------------------- */
.callbar {
  position: fixed;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 45;
  display: flex;
  background: var(--accent);
  padding-bottom: env(safe-area-inset-bottom, 0px);
}
.callbar a {
  flex: 1;
  min-height: 58px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
  font-family: var(--font-display);
  font-size: 0.9375rem;
  font-weight: 700;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--ink);
  text-decoration: none;
}
.callbar a + a {
  border-left: 1px solid rgba(10, 10, 10, 0.22);
}

@media (min-width: 900px) {
  .callbar {
    display: none;
  }
  body {
    padding-bottom: 0;
  }
}

/* -------------------------------------------------------------------------
   15. Consent banner
   ------------------------------------------------------------------------- */
.consent {
  position: fixed;
  z-index: 60;
  left: 0;
  right: 0;
  bottom: 0;
  background: var(--ink);
  color: var(--on-ink);
  border-top: 2px solid var(--accent);
  padding: 20px var(--gutter) calc(20px + env(safe-area-inset-bottom, 0px));
}
.consent[hidden] {
  display: none !important;
}
.consent__inner {
  max-width: var(--rail);
  margin-inline: auto;
  display: grid;
  gap: 16px;
}
.consent__title {
  font-size: 1.0625rem;
  margin-bottom: 7px;
}
.consent__body {
  margin: 0;
  font-size: 0.875rem;
  line-height: 1.6;
  color: var(--on-ink-dim);
  max-width: 76ch;
}
.consent__btns {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
}
.consent__btns .btn {
  flex: 1 1 150px;
  min-height: 48px;
  font-size: 0.8125rem;
}
@media (min-width: 900px) {
  .consent__inner {
    grid-template-columns: 1fr auto;
    align-items: center;
    gap: 32px;
  }
  .consent__btns {
    flex-wrap: nowrap;
  }
}

/* When the consent banner is up it sits above the call bar. */
body:has(.consent:not([hidden])) .callbar {
  display: none;
}

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

/* -------------------------------------------------------------------------
   Animated diagrams (service heroes)

   The finished, powered state is the default: it is what anyone without scripting, or with
   reduced motion, sees. Only when both scripting and motion are available does the diagram
   start dark and power itself on as it scrolls into view. See _includes/diagrams/_parts.njk
   for how each wire is layered.
   ------------------------------------------------------------------------- */
.hero__visual {
  margin-top: clamp(34px, 8vw, 52px);
}
@media (min-width: 1000px) {
  .hero__inner--split {
    display: grid;
    grid-template-columns: minmax(0, 1.08fr) minmax(0, 0.92fr);
    gap: clamp(32px, 4vw, 64px);
    align-items: center;
  }
  .hero__visual {
    margin-top: 0;
  }
}

.dg {
  --dg-line: var(--on-ink);
  --dg-wire: rgba(242, 243, 240, 0.26);
  --dg-energy: var(--accent);
  position: relative;
  margin: 0;
  max-width: 440px;
}
@media (min-width: 1000px) {
  .dg {
    margin-left: auto;
  }
}
.dg__svg {
  display: block;
  width: 100%;
  height: auto;
}

.dg-part {
  fill: none;
  stroke: var(--dg-line);
  stroke-width: 1.6;
  stroke-linejoin: round;
  stroke-linecap: round;
  opacity: 0.85;
}
.dg-part--thin {
  stroke-width: 1;
  opacity: 0.4;
}
.dg-ground {
  stroke: var(--dg-ground, var(--rule-ink));
  stroke-width: 1;
}
.dg-panel {
  fill: rgba(139, 197, 63, 0.1);
}
.dg-pin {
  fill: var(--dg-line);
  opacity: 0.85;
}
.dg-sun {
  fill: none;
  stroke: var(--dg-line);
  stroke-width: 1.6;
}
.dg-rays line {
  stroke: var(--dg-line);
  stroke-width: 1.6;
  stroke-linecap: round;
}
.dg-leader {
  stroke: var(--dg-wire);
  stroke-width: 1;
}
.dg-arrowhead {
  fill: var(--dg-energy);
}
.dg-label {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: 14px;
  letter-spacing: 0.08em;
  fill: var(--on-ink-dim);
}
.dg-label--energy {
  fill: var(--dg-energy);
}
.dg-label--small {
  font-size: 12px;
}

/* Service area map (contact page). */
.dg-area {
  fill: var(--dg-energy);
  opacity: 0.12;
}
.dg-zone {
  fill: var(--dg-energy);
  fill-opacity: 0.07;
  stroke: var(--dg-energy);
  stroke-width: 1;
  stroke-dasharray: 4 4;
  stroke-opacity: 0.55;
}
.dg-grid-line {
  stroke: var(--dg-wire);
  stroke-width: 0.6;
  opacity: 0.5;
}
.dg-city {
  fill: var(--dg-line);
}
.dg-pin {
  fill: var(--dg-energy);
}
.dg-pin-dot {
  fill: var(--ink);
}
/* Map labels get a halo in the background colour, so a boundary running under a label breaks
   around the letters rather than through them. */
.dg--map .dg-label {
  paint-order: stroke;
  stroke: var(--ink);
  stroke-width: 4px;
  stroke-linejoin: round;
}
.dg-credit {
  font-family: var(--font-body);
  font-size: 10px;
  fill: var(--on-ink-dim);
}

.dg-wire {
  fill: none;
  stroke: var(--dg-wire);
  stroke-width: 1.4;
}
/* Butt caps: a round cap would leave a dot at the start of an undrawn path. */
.dg-charge {
  fill: none;
  stroke: var(--dg-energy);
  stroke-width: 2.4;
  stroke-linecap: butt;
  stroke-dasharray: 1;
  stroke-dashoffset: 0;
  opacity: 0.28;
}
.dg-flow {
  fill: none;
  stroke: var(--dg-energy);
  stroke-width: 2.2;
  stroke-linecap: round;
  stroke-dasharray: 5 9;
}
.dg-flow--photon {
  stroke-width: 1.6;
  stroke-dasharray: 2 10;
}
.dg-lamp {
  fill: var(--dg-energy);
  opacity: 0.35;
}
.dg-level {
  fill: var(--dg-energy);
  opacity: 0.55;
  transform-box: fill-box;
  transform-origin: 50% 100%;
}
/* Drawings on a light surface, such as the home page buildings. Current takes the deep
   accent there: the bright one is too pale for a thin line on paper. */
.dg--paper {
  --dg-line: var(--on-paper);
  --dg-wire: rgba(10, 10, 10, 0.22);
  --dg-energy: var(--accent-deep);
  --dg-ground: rgba(10, 10, 10, 0.3);
}
.dg-glow {
  fill: var(--accent);
  opacity: 0.45;
}
.dg-lit {
  fill: var(--accent);
  opacity: 0.5;
}
/* Play-once drawings keep their current fully drawn instead of settling behind a flow. */
.dg--once .dg-charge {
  opacity: 1;
}
.dg-charging {
  fill: var(--dg-energy);
  opacity: 0.55;
  transform-box: fill-box;
  transform-origin: 0 50%;
}
.dg-moon {
  fill: none;
  stroke: var(--dg-line);
  stroke-width: 1.6;
}
/* Evening-only pieces. The static drawing is the daytime one, and a "return" current laid
   over its conductor would only double the dash pattern there. */
.dg-sky--night,
.dg-time,
.dg-charge.dg-return,
.dg-flow.dg-return {
  opacity: 0;
}

/* Power-on sequence. */
.dg-s0 {
  --dg-at: 0s;
}
.dg-s1 {
  --dg-at: 0.45s;
}
.dg-s2 {
  --dg-at: 0.9s;
}
.dg-s3 {
  --dg-at: 1.35s;
}
.dg-s4 {
  --dg-at: 1.8s;
}

@media (scripting: enabled) and (prefers-reduced-motion: no-preference) {
  .dg:not(.is-live) .dg-charge {
    stroke-dashoffset: 1;
    opacity: 1;
  }
  .dg:not(.is-live) .dg-flow,
  .dg:not(.is-live) .dg-lamp {
    opacity: 0;
  }

  .dg.is-live .dg-charge {
    animation:
      dg-charge 0.55s cubic-bezier(0.45, 0, 0.25, 1) var(--dg-at) both,
      dg-settle 0.7s ease calc(var(--dg-at) + 0.55s) both;
  }
  .dg.is-live .dg-flow {
    animation:
      dg-appear 0.5s ease calc(var(--dg-at) + 0.5s) both,
      dg-flow 1.1s linear calc(var(--dg-at) + 0.5s) infinite;
  }
  .dg.is-live .dg-flow--photon {
    animation-name: dg-appear, dg-photon;
    animation-duration: 0.5s, 0.9s;
  }
  .dg.is-live .dg-lamp {
    animation:
      dg-lamp-on 0.45s ease calc(var(--dg-at) + 0.5s) both,
      dg-glow 2.6s ease-in-out calc(var(--dg-at) + 0.95s) infinite;
  }
  .dg.is-live .dg-rays {
    animation: dg-breathe 3.2s ease-in-out infinite;
  }

  /* Play-once drawings. Nothing loops, so none of them needs a pause control. --dg-offset
     staggers neighbouring tiles so a row lights up building by building. */
  .dg--once:not(.is-live) .dg-glow,
  .dg--once:not(.is-live) .dg-lit,
  .dg--once:not(.is-live) .dg-area,
  .dg--once:not(.is-live) .dg-zone {
    opacity: 0;
  }
  .dg.dg--once.is-live .dg-zone {
    animation: dg-appear 0.6s ease calc(var(--dg-at) + var(--dg-offset, 0s) + 0.9s) both;
  }
  .dg.dg--once.is-live .dg-area {
    animation: dg-area-on 0.6s ease calc(var(--dg-at) + var(--dg-offset, 0s) + 0.45s) both;
  }
  .dg.dg--once.is-live .dg-charge {
    animation: dg-charge 0.55s cubic-bezier(0.45, 0, 0.25, 1) calc(var(--dg-at) + var(--dg-offset, 0s)) both;
  }
  .dg.dg--once.is-live .dg-glow {
    animation: dg-glow-on 0.5s ease calc(var(--dg-at) + var(--dg-offset, 0s)) both;
  }
  .dg.dg--once.is-live .dg-lit {
    animation: dg-lit-on 0.4s ease calc(var(--dg-at) + var(--dg-offset, 0s) + 0.3s) both;
  }

  /* Car charging: the indicator sweeps like a phone's for as long as current flows. */
  .dg:not(.is-live) .dg-charging {
    transform: scaleX(0.25);
  }
  .dg.is-live .dg-charging {
    animation: dg-charging 2.4s steps(4, jump-none) calc(var(--dg-at) + 0.95s) infinite both;
  }

  /* Day/night cycle (energy storage). One 16s clock for everything: day runs 0–50%, evening
     50–100%. Wires keep their step delay, so current retreats at dusk in the order it
     arrived. Fill modes must stay "both": the 0% keyframe is the unpowered start. */
  .dg:not(.is-live) .dg-level {
    transform: scaleY(0.25);
  }
  .dg.is-live .dg-charge.dg-day {
    animation: dg-day-charge 16s linear var(--dg-at) infinite both;
  }
  .dg.is-live .dg-flow.dg-day {
    animation:
      dg-day-flow 16s linear var(--dg-at) infinite both,
      dg-flow 1.1s linear var(--dg-at) infinite;
  }
  .dg.is-live .dg-flow--photon.dg-day {
    animation-name: dg-day-flow, dg-photon;
    animation-duration: 16s, 0.9s;
  }
  .dg.is-live .dg-charge.dg-night {
    animation: dg-night-charge 16s linear var(--dg-at) infinite both;
  }
  .dg.is-live .dg-flow.dg-night {
    animation:
      dg-night-flow 16s linear var(--dg-at) infinite both,
      dg-flow 1.1s linear var(--dg-at) infinite;
  }
  .dg.is-live .dg-lamp.dg-night {
    animation: dg-night-lamp 16s linear var(--dg-at) infinite both;
  }
  .dg.is-live .dg-sky--day {
    animation: dg-sky-day 16s linear infinite both;
  }
  .dg.is-live .dg-sky--night,
  .dg.is-live .dg-time--night {
    animation: dg-sky-night 16s linear infinite both;
  }
  .dg.is-live .dg-time--day {
    animation: dg-time-day 16s linear infinite both;
  }
  .dg.is-live .dg-level {
    animation: dg-level 16s steps(4, jump-none) infinite both;
  }

  .dg.is-paused *,
  .dg.is-offscreen * {
    animation-play-state: paused !important;
  }
}

/* Explicit 0% and 100% keyframes throughout: implicit ones read the underlying value, which
   is unreliable when two animations on an element target the same property. */
@keyframes dg-charge {
  0% { stroke-dashoffset: 1; }
  100% { stroke-dashoffset: 0; }
}
@keyframes dg-settle {
  0% { opacity: 1; }
  100% { opacity: 0.28; }
}
@keyframes dg-appear {
  0% { opacity: 0; }
  100% { opacity: 1; }
}
@keyframes dg-flow {
  0% { stroke-dashoffset: 0; }
  100% { stroke-dashoffset: -14; }
}
@keyframes dg-photon {
  0% { stroke-dashoffset: 0; }
  100% { stroke-dashoffset: -12; }
}
@keyframes dg-lamp-on {
  0% { opacity: 0; }
  100% { opacity: 0.35; }
}
/* Slow enough to stay far below the three-flashes-per-second limit. */
@keyframes dg-glow {
  0%, 100% { opacity: 0.35; }
  50% { opacity: 0.6; }
}
@keyframes dg-breathe {
  0%, 100% { opacity: 1; }
  50% { opacity: 0.5; }
}

@keyframes dg-area-on {
  0% { opacity: 0; }
  100% { opacity: 0.12; }
}
@keyframes dg-glow-on {
  0% { opacity: 0; }
  100% { opacity: 0.45; }
}
@keyframes dg-lit-on {
  0% { opacity: 0; }
  100% { opacity: 0.5; }
}
@keyframes dg-charging {
  0% { transform: scaleX(0.25); }
  100% { transform: scaleX(1); }
}

/* Day/night cycle. On the 16s clock 1s is 6.25%. The draw-in and settle timings match
   dg-charge and dg-settle above. A wire is only ever re-armed (dashoffset back to 1) while
   it is fully transparent. */
@keyframes dg-day-charge {
  0% { stroke-dashoffset: 1; opacity: 1; animation-timing-function: cubic-bezier(0.45, 0, 0.25, 1); }
  3.44% { stroke-dashoffset: 0; opacity: 1; animation-timing-function: ease; }
  7.81%, 50% { stroke-dashoffset: 0; opacity: 0.28; }
  53.75% { stroke-dashoffset: 0; opacity: 0; }
  54%, 99.5% { stroke-dashoffset: 1; opacity: 0; }
  100% { stroke-dashoffset: 1; opacity: 1; }
}
@keyframes dg-day-flow {
  0%, 3.13% { opacity: 0; }
  6.25%, 50% { opacity: 1; }
  53.75%, 100% { opacity: 0; }
}
/* Evening current starts at 60%, once the daytime charging current has faded out of the
   shared battery conductor. */
@keyframes dg-night-charge {
  0%, 60% { stroke-dashoffset: 1; opacity: 1; animation-timing-function: cubic-bezier(0.45, 0, 0.25, 1); }
  63.44% { stroke-dashoffset: 0; opacity: 1; animation-timing-function: ease; }
  67.81%, 92.5% { stroke-dashoffset: 0; opacity: 0.28; }
  96.25% { stroke-dashoffset: 0; opacity: 0; }
  96.5%, 99.5% { stroke-dashoffset: 1; opacity: 0; }
  100% { stroke-dashoffset: 1; opacity: 1; }
}
@keyframes dg-night-flow {
  0%, 63.13% { opacity: 0; }
  66.25%, 92.5% { opacity: 1; }
  96.25%, 100% { opacity: 0; }
}
@keyframes dg-night-lamp {
  0%, 63.13% { opacity: 0; }
  65.94% { opacity: 0.35; }
  74% { opacity: 0.55; }
  82% { opacity: 0.35; }
  88.5% { opacity: 0.55; }
  92.5% { opacity: 0.4; }
  96.25%, 100% { opacity: 0; }
}
/* The sun is fully up before its light reaches the panel at 0%. */
@keyframes dg-sky-day {
  0%, 46.25% { opacity: 1; }
  50%, 93.75% { opacity: 0; }
  97.5%, 100% { opacity: 1; }
}
@keyframes dg-sky-night {
  0%, 50% { opacity: 0; }
  53.75%, 92.5% { opacity: 1; }
  96.25%, 100% { opacity: 0; }
}
@keyframes dg-time-day {
  0% { opacity: 0; }
  3.75%, 46.25% { opacity: 1; }
  50%, 100% { opacity: 0; }
}
/* Charges through the day, drains through the evening, never below the reserve cell. */
@keyframes dg-level {
  0%, 12.5% { transform: scaleY(0.25); }
  43.75%, 66.25% { transform: scaleY(1); }
  93.75%, 100% { transform: scaleY(0.25); }
}

/* Pause control. WCAG 2.2.2 requires motion that runs longer than five seconds to be
   stoppable. Top-right, which every drawing keeps clear. */
.dg__toggle {
  position: absolute;
  top: 0;
  right: 0;
  width: 44px;
  height: 44px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 0;
  background: var(--ink);
  color: var(--on-ink-dim);
  border: 1px solid var(--rule-ink);
  cursor: pointer;
  transition: color 0.16s ease, border-color 0.16s ease;
}
.dg__toggle[hidden] {
  display: none;
}
.dg__toggle:hover {
  color: var(--accent);
  border-color: var(--accent);
}
.dg__icon {
  width: 14px;
  height: 14px;
  fill: currentColor;
}
.dg__icon--play,
.dg__toggle[aria-pressed="true"] .dg__icon--pause {
  display: none;
}
.dg__toggle[aria-pressed="true"] .dg__icon--play {
  display: block;
}
