/* Power On Electric LLC
   Palette taken from the business card artwork: #00C256 green, #2C2C2C dark,
   #F9F9F9 stock. The green fails text contrast on white, so it is used for
   graphic elements only; --brand-ink is the darkened version for type.

   The page is set like a drawing sheet: a heavy border, a title block along
   the bottom carrying the legal line, and three line weights used the way a
   drawing uses them - heavy for the sheet, medium for structure, hairline for
   the lists. He bids lump sum off drawings; this is the register his readers
   already work in. */

/* Self-hosted rather than loaded from Google. The hosted version cost two extra
   DNS + TLS handshakes and an 11.7 KB render-blocking stylesheet on a third-party
   origin before the first glyph could even be requested, and disclosed every
   visitor's IP to Google. These are the same woff2 files Google serves, latin
   subset only - every character either page renders is inside that range.
   All three families are SIL Open Font License 1.1; see assets/fonts/README.md.
   Archivo is a variable font, so one file covers both weights we use. */

@font-face {
  font-family: "Archivo";
  font-style: normal;
  font-weight: 500 600;
  font-display: swap;
  src: url("assets/fonts/archivo-var.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+2074,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD;
}

@font-face {
  font-family: "Public Sans";
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url("assets/fonts/public-sans-400.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+2074,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-weight: 400;
  font-display: swap;
  src: url("assets/fonts/ibm-plex-mono-400.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+2074,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-weight: 500;
  font-display: swap;
  src: url("assets/fonts/ibm-plex-mono-500.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+2074,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD;
}

:root {
  --brand:      #00C256;
  --brand-ink:  #007a38;
  --ink:        #2C2C2C;
  --ink-soft:   #5f6866;
  --paper:      #ffffff;
  --paper-2:    #f9f9f9;
  --line:       #b9c0bd;   /* medium weight: structure */
  --rule:       #e3e7e5;   /* hairline: lists */
  --focus:      #007a38;

  --font-display: "Archivo", "Helvetica Neue", Arial, sans-serif;
  --font-body: "Public Sans", -apple-system, "Segoe UI", Roboto, sans-serif;
  --font-mono: "IBM Plex Mono", ui-monospace, "Cascadia Mono", Consolas, monospace;

  /* Sheet geometry. The sheet sits a gutter in from the viewport on the card's
     stock; content sits a pad in from its edge. The corner radius is the card's
     own proportion (17pt on a 503pt card). */
  --gutter: clamp(10px, 1.6vw, 24px);
  --pad:    clamp(20px, 3.2vw, 48px);
  --radius: clamp(14px, 3.3vw, 46px);

  color-scheme: light;
}

/* Both dark palettes are scoped to screen. They are more specific than the
   :root overrides in the print block at the foot of this file, so without
   this they win during printing: prefers-color-scheme still matches, the
   paper stays white because browsers omit backgrounds, and the page prints
   as near-white text on white - including the legally required footer. */
@media screen and (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --brand:      #00d15d;
    --brand-ink:  #35dd7c;
    --ink:        #e9edeb;
    --ink-soft:   #9aa4a0;
    --paper:      #151917;
    --paper-2:    #1c211e;
    --line:       #4a524e;
    --rule:       #2b312e;
    --focus:      #35dd7c;
    color-scheme: dark;
  }
  /* The P's gradient is two dark greys; on dark paper it is lifted to two light
     ones, keeping the highlight direction. Lives here rather than as tokens
     because SVG stops cannot take a var() through the gradient's own scope. */
  :root:not([data-theme="light"]) .st-p0 { stop-color: #dfe4e1; }
  :root:not([data-theme="light"]) .st-p1 { stop-color: #f2f5f3; }
}

/* `data-theme` is a manual override and nothing on either page sets it. It is
   here so either palette can be forced from devtools - set data-theme on <html> -
   without changing the OS setting, which is also how the print behaviour above
   is checked. The :not([data-theme="light"]) guard on the query above is the
   other half of it. Deliberate, not a leftover. */
@media screen {
  :root[data-theme="dark"] .st-p0 { stop-color: #dfe4e1; }
  :root[data-theme="dark"] .st-p1 { stop-color: #f2f5f3; }
  :root[data-theme="dark"] {
    --brand:      #00d15d;
    --brand-ink:  #35dd7c;
    --ink:        #e9edeb;
    --ink-soft:   #9aa4a0;
    --paper:      #151917;
    --paper-2:    #1c211e;
    --line:       #4a524e;
    --rule:       #2b312e;
    --focus:      #35dd7c;
    color-scheme: dark;
  }
}

* { box-sizing: border-box; }

html, body { margin: 0; }

body {
  background: var(--paper-2);
  color: var(--ink);
  font-family: var(--font-body);
  font-size: 17px;
  line-height: 1.55;
  -webkit-font-smoothing: antialiased;
  padding: var(--gutter);
}

a { color: var(--brand-ink); }

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

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

/* ---------------- Sheet ---------------- */

/* One sheet, set like the card: rounded, on the card's stock, the card's own
   bands along its top and bottom edges. The bands are the sheet's frame. */
.sheet {
  background: var(--paper);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  min-height: calc(100vh - 2 * var(--gutter));
  min-height: calc(100dvh - 2 * var(--gutter));
  max-width: 104rem;
  margin-inline: auto;
  display: flex;
  flex-direction: column;
  overflow: hidden;   /* the bands run under the rounded corners */
}

/* The card's bands, rebuilt as vectors from the PDF: the dark shape, its
   paper-coloured gap, the green shape with its gradient, and the facets. Drawn
   at the card's own proportion, so their height follows the sheet's width. */
.band {
  display: block;
  width: 100%;
  height: auto;
  aspect-ratio: 502.94 / 46;
  flex: none;
}

.band__dark {
  fill: #2c2c2c;             /* the card's dark, a brand constant in both themes */
  stroke: var(--paper);      /* the gap between dark and green is the paper showing */
  stroke-linejoin: round;
}

.body {
  flex: 1 0 auto;
  display: flex;
  flex-direction: column;
}

/* ---------------- Masthead ---------------- */

.masthead {
  display: grid;
  grid-template-columns: auto auto 1fr;
  align-items: center;
  gap: 16px 0;
  padding: calc(var(--pad) * 0.6) var(--pad);
  border-bottom: 1px solid var(--line);
}

.lockup {
  display: block;
  width: clamp(176px, 17vw, 256px);
  padding-right: var(--pad);
  color: inherit;
}

.lockup__svg {
  display: block;
  width: 100%;
  height: auto;
  aspect-ratio: 261.44 / 113.53;
  overflow: visible;
}

.lockup__ink   { fill: var(--ink); }
.lockup__brand { fill: var(--brand); }

/* A cell beside the lockup, the rule running the masthead's full height. */
.masthead__id {
  margin: 0;
  align-self: stretch;
  display: flex;
  align-items: center;
  padding-left: var(--pad);
  border-left: 1px solid var(--line);
  font-family: var(--font-display);
  font-weight: 500;
  font-size: 0.98rem;
  line-height: 1.35;
  letter-spacing: -0.005em;
  color: var(--ink-soft);
}

.masthead__tel {
  justify-self: end;
  display: grid;
  gap: 2px;
  text-align: right;
  text-decoration: none;
  color: inherit;
  white-space: nowrap;
}

.masthead__tel-label {
  font-family: var(--font-mono);
  font-size: 10.5px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--ink-soft);
}

.masthead__tel-num {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: 1.2rem;
  letter-spacing: -0.015em;
  font-variant-numeric: tabular-nums;
}

.masthead__tel:hover .masthead__tel-num { color: var(--brand-ink); }

/* ---------------- Cover ---------------- */

/* The statement and, beside it, his mark at the height of the cover, with its
   real gradients - the one place the page spends anything. */
.cover {
  --cover-pad-t: clamp(40px, 6vw, 96px);
  --cover-pad-b: clamp(36px, 5vw, 80px);
  position: relative;
  display: grid;
  grid-template-columns: minmax(0, 7fr) minmax(0, 5fr);
  align-items: end;
  padding: var(--cover-pad-t) var(--pad) var(--cover-pad-b);
  border-bottom: 1px solid var(--line);
  min-height: 52vh;
}

.statement {
  margin: 0;
  font-family: var(--font-display);
  font-weight: 600;
  font-size: clamp(2.35rem, 1rem + 4.7vw, 5.4rem);
  line-height: 1.02;
  letter-spacing: -0.03em;
  text-wrap: balance;
  max-width: 16ch;
}

/* "projects" is the word that quietly sets the scale of the work,
   so it is the one thing in the statement the green is spent on. */
.statement em {
  font-style: normal;
  color: var(--brand-ink);
}

/* The mark, at the height of the cover's content box, tip of the bolt on the rule.
   Two stacked drawings in one box: the P (with the intro linework) underneath,
   the bolt on its own layer above so its ambient motion runs on the compositor
   and repaints only itself. They never overlap, so the order is free. */
.cover__mark {
  position: absolute;
  right: var(--pad);
  bottom: var(--cover-pad-b);
  height: calc(100% - var(--cover-pad-t) - var(--cover-pad-b));
  width: auto;
  aspect-ratio: 88.66 / 112.1;
  pointer-events: none;
  will-change: filter;
  animation: power-glow 1.6s ease-out 1.05s both,
             glow-breathe 5s ease-in-out 2.65s infinite;
}

.cover__mark > svg {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  overflow: visible;
}

/* ---- Ambient, after the intro: the bolt is live. ----
   A slow sway about its tip, a sheen that sweeps it every seven seconds, the
   glow breathing, and three sparks at the tip that flash on cycles of 7.3, 11.1
   and 13.7 seconds - coprime, so the pattern does not repeat for hours and
   never reads as a metronome. All of it starts once the linework has faded. */
.mark__boltlayer {
  transform-origin: 2% 98%;   /* the tip of the bolt */
  will-change: transform;
  animation: sway 9s ease-in-out 2.8s infinite;
}

@keyframes sway {
  0%   { transform: rotate(0deg) translateX(0); }
  25%  { transform: rotate(0.7deg) translateX(0.35%); }
  75%  { transform: rotate(-0.7deg) translateX(-0.35%); }
  100% { transform: rotate(0deg) translateX(0); }
}

.mark__sheen {
  opacity: 0;
  animation: sheen 7s cubic-bezier(0.45, 0, 0.55, 1) 3.4s infinite;
}

@keyframes sheen {
  0%   { transform: translateX(-52px); opacity: 0; }
  2%   { opacity: 1; }
  17%  { transform: translateX(54px); opacity: 1; }
  19%  { transform: translateX(54px); opacity: 0; }
  100% { transform: translateX(54px); opacity: 0; }
}

.mark__spark {
  fill: none;
  stroke: var(--brand);
  stroke-width: 0.5;
  stroke-linecap: round;
  stroke-linejoin: round;
  opacity: 0;
  animation: zap var(--cycle, 9s) steps(1, end) var(--delay, 4s) infinite;
}

.mark__spark:nth-child(1) { --cycle: 7.3s;  --delay: 3.6s; }
.mark__spark:nth-child(2) { --cycle: 11.1s; --delay: 6.9s; }
.mark__spark:nth-child(3) { --cycle: 13.7s; --delay: 9.5s; }

@keyframes zap {
  0%   { opacity: 0; }
  1.2% { opacity: 1; }
  2.4% { opacity: 0; }
  3.2% { opacity: 0.85; }
  4.4% { opacity: 0; }
  100% { opacity: 0; }
}

@keyframes glow-breathe {
  0%, 100% { filter: drop-shadow(0 0 10px rgba(0, 194, 86, 0.22)); }
  50%      { filter: drop-shadow(0 0 17px rgba(0, 194, 86, 0.42)); }
}

/* "Power on", once, on load. The mark is drawn as linework first, the way it
   would go down on a sheet; then the bolt strikes - it flickers in like a tube
   striking, with a bloom of green that settles to a faint glow - and the P
   fills in behind it while the linework fades. About two and a half seconds,
   never repeated; reduced-motion gets the finished mark. Stroke widths are in
   viewBox units so they scale with the drawing; non-scaling-stroke is avoided
   because it also rescales the dash pattern and breaks the draw-on. */
.mark__line {
  fill: none;
  stroke: var(--ink-soft);
  stroke-width: 0.3;
  stroke-linejoin: miter;
  stroke-dasharray: 1;
  stroke-dashoffset: 1;
  animation: draw 0.9s cubic-bezier(0.55, 0, 0.2, 1) 0.1s forwards,
             line-out 0.5s ease-out 1.5s forwards;
}

.mark__line--bolt { stroke: var(--brand); }

.mark__fill .mark-p {
  opacity: 0;
  animation: fill-in 0.8s ease-out 1.35s forwards;
}

.mark__fill .mark-bolt {
  opacity: 0;
  animation: strike 0.75s linear 1s forwards;
}

@keyframes draw     { to { stroke-dashoffset: 0; } }
@keyframes line-out { to { opacity: 0; } }
@keyframes fill-in  { to { opacity: 1; } }

@keyframes strike {
  0%   { opacity: 0; }
  8%   { opacity: 1; }
  16%  { opacity: 0.15; }
  30%  { opacity: 1; }
  38%  { opacity: 0.4; }
  50%  { opacity: 1; }
  100% { opacity: 1; }
}

@keyframes power-glow {
  0%   { filter: drop-shadow(0 0 0 rgba(0, 194, 86, 0)); }
  25%  { filter: drop-shadow(0 0 28px rgba(0, 194, 86, 0.75)); }
  100% { filter: drop-shadow(0 0 10px rgba(0, 194, 86, 0.22)); }
}

/* 404 only */
.cover--notfound {
  grid-template-columns: minmax(0, 1fr);
  min-height: 0;
  border-bottom: 0;
}

.cover__aside {
  margin: 28px 0 0;
  font-family: var(--font-display);
  font-weight: 500;
  font-size: 1.05rem;
}

/* ---------------- Sectors ---------------- */

.sectors__list {
  margin: 0;
  padding: 0 var(--pad);
  list-style: none;
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  border-bottom: 1px solid var(--line);
}

.sector {
  padding: 22px 20px 24px 0;
  font-family: var(--font-display);
  font-weight: 500;
  font-size: clamp(1.05rem, 0.9rem + 0.6vw, 1.35rem);
  letter-spacing: -0.015em;
  line-height: 1.2;
}

.sector + .sector {
  padding-left: 20px;
  border-left: 1px solid var(--line);
}

/* A graphic use of the raw brand green, not body text, so the text-contrast
   floor that rules out --brand for type does not apply here. */
.sector::before {
  content: "";
  display: block;
  width: 20px;
  height: 3px;
  margin-bottom: 12px;
  background: var(--brand);
}

/* ---------------- Scope ---------------- */

.scope {
  display: grid;
  grid-template-columns: minmax(0, 5fr) minmax(0, 7fr);
  gap: 24px var(--pad);
  padding: clamp(32px, 4vw, 56px) var(--pad);
  border-bottom: 1px solid var(--line);
}

.scope__h {
  margin: 0;
  font-family: var(--font-display);
  font-weight: 600;
  font-size: clamp(1.4rem, 1.1rem + 1.1vw, 2rem);
  letter-spacing: -0.025em;
  line-height: 1.1;
}

.scope__note {
  margin: 14px 0 0;
  max-width: 34ch;
  font-size: 1.02rem;
  line-height: 1.5;
  color: var(--ink-soft);
}

/* Two columns of four, read down then across, the way a schedule reads. */
.scope__list {
  margin: 0;
  padding: 0;
  list-style: none;
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  grid-auto-flow: column;
  grid-template-rows: repeat(4, auto);
  column-gap: var(--pad);
}

.scope__list li {
  padding: 12px 0 13px;
  border-top: 1px solid var(--rule);
  font-size: 1.02rem;
  line-height: 1.4;
}

/* ---------------- Record ---------------- */

.record {
  padding: clamp(32px, 4vw, 56px) var(--pad) clamp(40px, 5vw, 72px);
}

.record__list {
  margin: 0;
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  column-gap: var(--pad);
}

.record__row {
  display: grid;
  gap: 10px;
  align-content: start;
}

.record__row + .record__row {
  padding-left: var(--pad);
  margin-left: calc(var(--pad) * -1);
  border-left: 1px solid var(--line);
}

.record__row dt {
  font-family: var(--font-display);
  font-weight: 500;
  font-size: 0.92rem;
  letter-spacing: -0.005em;
  color: var(--ink-soft);
}

.record__row dd {
  margin: 0;
  display: grid;
  gap: 6px;
  font-size: 1.02rem;
  line-height: 1.45;
}

.record__lead {
  font-family: var(--font-display);
  font-weight: 500;
  font-size: clamp(1.1rem, 1rem + 0.5vw, 1.35rem);
  letter-spacing: -0.015em;
  line-height: 1.25;
}

.record__sub {
  color: var(--ink-soft);
  font-size: 0.95rem;
}

/* The permit is the one number the client publishes, and the reason most
   visitors are here, so it is set as a figure rather than tucked under a label. */
.permit {
  display: grid;
  gap: 2px;
  margin-top: 6px;
  font-family: var(--font-mono);
}

.permit__label {
  font-size: 0.8rem;
  letter-spacing: 0.01em;
  color: var(--ink-soft);
}

.permit__val {
  font-size: clamp(1.15rem, 1rem + 0.7vw, 1.55rem);
  font-weight: 500;
  letter-spacing: 0.04em;
  line-height: 1.2;
}

.record__contact a {
  font-family: var(--font-display);
  font-weight: 500;
  font-size: clamp(1.1rem, 1rem + 0.5vw, 1.35rem);
  letter-spacing: -0.015em;
  line-height: 1.45;   /* keeps the tap target above 24px at the smallest size */
  text-decoration: none;
  overflow-wrap: anywhere;
}

.record__contact a:hover { text-decoration: underline; text-underline-offset: 0.15em; }

/* ---------------- Title block ---------------- */

/* The legally required line, set as the sheet's title block. One paragraph,
   three cells, prescribed order. */
.titleblock {
  border-top: 1px solid var(--line);
  border-bottom: 1px solid var(--line);
  background: var(--paper-2);
}

.titleblock__line {
  margin: 0;
  display: grid;
  grid-template-columns: minmax(0, 4fr) minmax(0, 6fr) minmax(0, 3fr);
  font-family: var(--font-mono);
  font-size: 0.78rem;
  line-height: 1.5;
  letter-spacing: 0.01em;
  color: var(--ink);
}

.titleblock__cell {
  padding: 14px var(--pad);
}

.titleblock__cell + .titleblock__cell {
  border-left: 1px solid var(--line);
}

/* ---------------- Narrow ---------------- */

@media (max-width: 64rem) {
  .cover { grid-template-columns: minmax(0, 1fr); min-height: 0; }
  .statement { max-width: 18ch; }
  .scope { grid-template-columns: minmax(0, 1fr); }
  .record__list { grid-template-columns: minmax(0, 1fr); row-gap: 28px; }
  .record__row + .record__row {
    padding-left: 0;
    margin-left: 0;
    border-left: 0;
    padding-top: 24px;
    border-top: 1px solid var(--rule);
  }
}

@media (max-width: 44rem) {
  body { font-size: 16px; }
  .masthead {
    grid-template-columns: 1fr auto;
    align-items: center;
    row-gap: 14px;
  }
  .masthead__id {
    grid-column: 1 / -1;
    grid-row: 2;
    padding: 12px 0 0;
    border-left: 0;
    border-top: 1px solid var(--rule);
  }
  .lockup { width: 168px; padding-right: 16px; }
  .statement { max-width: none; }
  /* In flow on a phone: under the statement, right-aligned, its own height. */
  .cover__mark {
    position: static;
    height: clamp(200px, 36vh, 300px);
    margin: 28px 0 0 auto;
  }
  .mark__line { stroke-width: 0.5; }
  .sectors__list { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .sector { padding: 16px 16px 18px 0; }
  .sector + .sector { padding-left: 16px; }
  .sector:nth-child(3) { padding-left: 0; border-left: 0; }
  .sector:nth-child(n + 3) { border-top: 1px solid var(--line); }
  .scope__list { grid-template-columns: minmax(0, 1fr); grid-auto-flow: row; grid-template-rows: none; }
  .titleblock__line { grid-template-columns: minmax(0, 1fr); }
  .titleblock__cell { padding: 10px var(--pad); }
  .titleblock__cell + .titleblock__cell { border-left: 0; border-top: 1px solid var(--line); }
}

@media (prefers-reduced-motion: reduce) {
  .cover__mark { animation: none; filter: none; }
  .mark__boltlayer { animation: none; }
  .mark__line, .mark__sheen, .mark__spark { animation: none; opacity: 0; }
  .mark__fill .mark-p, .mark__fill .mark-bolt { animation: none; opacity: 1; }
  * { transition-duration: 0.01ms !important; }
}

/* ---------------- Print ---------------- */

@media print {
  :root {
    --paper: #fff; --paper-2: #fff; --ink: #000;
    --ink-soft: #444;
    --line: #999; --rule: #ddd;
    --gutter: 0px;
  }
  body { font-size: 11pt; padding: 0; }
  .sheet { min-height: 0; max-width: none; border-radius: 0; }
  /* Set the variables rather than padding-block. .cover__mark positions itself
     against --cover-pad-t/-b - an absolute `bottom`, and a height calc off both -
     so overriding the padding alone leaves the mark's box and the cover's box
     disagreeing, and at a narrow paper width that height calc trends to zero. */
  .cover { min-height: 0; --cover-pad-t: 28pt; --cover-pad-b: 28pt; }
  .statement { font-size: 28pt; }
  .cover__mark { animation: none; filter: none; }
  .mark__boltlayer { animation: none; }
  .mark__line, .mark__sheen, .mark__spark { animation: none; opacity: 0; }
  .mark__fill .mark-p, .mark__fill .mark-bolt { animation: none; opacity: 1; }
  .band__dark { stroke: #fff; }
  .record__contact a { color: var(--ink); }
}
