/*
  Neural Grain site styles (PLAN-ng-site §4), in CUBE order:
  1. Global  2. Compositions  3. Utilities  4. Blocks  5. Exceptions

  - Mobile-first: the defaults are the 390 board; `min-width: 40rem` and up
    reach toward the 1440 board.
  - Every color is a token from tokens.css, or currentColor. No literals
    (tests/test_ng_color_literals.py).
  - Interactive states use the three tools only: line (an underline or a
    rule), screen, solid. No brightness, opacity or tint change to an ink
    (PLAN §8 Chunk 1).
  - `[data-state]` selectors exist so the /system/ specimen can show a state
    at rest for review; nothing else sets them.
  - URLs below carry `?v=<first 10 hex of sha256>`; tests/test_ng_assets.py
    fails if a file's bytes change and its `?v=` doesn't.
*/

/* ---------------------------------------------------------------- 1. Global */

@font-face {
  font-family: "Archivo Variable";
  font-style: normal;
  /* optional: with the preload, the font is ready for first paint on most
     loads; when it isn't, the page keeps the fallback rather than swapping
     to a 125%-wide face later (no layout shift; CLS 0 on home). */
  font-display: optional;
  font-weight: 100 900;
  font-stretch: 62% 125%;
  src: url("../../fonts/archivo-latin-wdth-normal.woff2?v=e3a28eade2") format("woff2");
}

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

html {
  color-scheme: light;
  background-color: var(--paper);
  color: var(--ink);
  font-family: var(--font-sans);
  -webkit-text-size-adjust: 100%;
  text-size-adjust: 100%;
}

body {
  /* The containing block for page-level fields (the home's grain field). */
  position: relative;
  margin: 0;
  min-block-size: 100vh;
  min-block-size: 100dvh;
  display: flex;
  flex-direction: column;
  font-size: var(--step-body);
  font-weight: var(--weight-body);
  font-stretch: var(--wdth-body);
  line-height: var(--leading-body);
  /* Fields bleed off the viewport edge; clip, so the page never scrolls sideways. */
  overflow-x: clip;
}

main {
  flex: 1 0 auto;
}

/* The skip link's target takes focus programmatically; it needs no ring. */
main:focus {
  outline: none;
}

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

h1,
h2,
h3 {
  font-weight: var(--weight-display);
  font-stretch: var(--wdth-display);
  line-height: var(--leading-display);
  letter-spacing: var(--tracking-display);
  text-wrap: balance;
}

p {
  text-wrap: pretty;
}

img,
picture,
svg {
  display: block;
  max-inline-size: 100%;
}

table {
  border-collapse: collapse;
}

/* `hidden` wins over any class that sets display (.stack is flex), so the
   download's notices stay hidden until their trigger (PLAN-purchase-path
   §2.2; RULING-purchase-path-gate1 R5). */
[hidden] {
  display: none !important;
}

/* The rule takes the ink: without `color`, the UA's gray would draw it (S2). */
hr {
  margin: 0;
  border: 0;
  border-block-start: var(--rule) solid;
  color: inherit;
}

/* Links: with one ink, the underline is the only cue (S9). Hover thickens
   it; active pulls it tight to the text. */
a {
  color: inherit;
  text-decoration-line: underline;
  text-decoration-thickness: var(--rule);
  text-underline-offset: 0.3em;
}

a:hover,
a[data-state="hover"] {
  text-decoration-thickness: calc(var(--rule) * 2);
}

a:active,
a[data-state="active"] {
  text-decoration-thickness: calc(var(--rule) * 2);
  text-underline-offset: 0.15em;
}

:focus-visible,
[data-state="focus"] {
  outline: var(--focus-ring);
  outline-offset: var(--focus-offset);
}

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

/* ---------------------------------------------------------- 2. Compositions */

.wrapper {
  inline-size: 100%;
  max-inline-size: 90rem;
  margin-inline: auto;
  padding-inline: var(--space-gutter);
}

.stack {
  display: flex;
  flex-direction: column;
  justify-content: flex-start;
}

.stack > * + * {
  margin-block-start: var(--stack-space, 1.5rem);
}

.cluster {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--cluster-space, 0.5rem 2rem);
}

/* Two columns that stack when the first can't keep its width: the boards'
   560px + 1fr layouts. */
.sidebar {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sidebar-space, 5rem);
}

.sidebar > :first-child {
  flex-basis: var(--sidebar-width, 35rem);
  flex-grow: 1;
}

.sidebar > :last-child {
  flex-basis: 0;
  flex-grow: 999;
  min-inline-size: 50%;
}

.grid {
  display: grid;
  gap: var(--grid-space, 2rem);
  grid-template-columns: repeat(auto-fit, minmax(min(var(--grid-min, 16rem), 100%), 1fr));
}

/* ------------------------------------------------------------- 3. Utilities */

.visually-hidden {
  position: absolute !important;
  inline-size: 1px !important;
  block-size: 1px !important;
  margin: -1px !important;
  padding: 0 !important;
  overflow: hidden !important;
  clip: rect(0 0 0 0) !important;
  white-space: nowrap !important;
  border: 0 !important;
}

.text-display {
  font-weight: var(--weight-display);
  font-stretch: var(--wdth-display);
  line-height: var(--leading-display);
  letter-spacing: var(--tracking-display);
}

.text-label {
  font-weight: var(--weight-label);
  font-stretch: var(--wdth-label);
}

/* Interface text the boards draw at 500 (S7, D18): header and nav links,
   the header email, footer rows. */
.text-ui {
  font-weight: var(--weight-ui);
}

.text-hero-home {
  font-size: var(--step-hero-home);
  line-height: 0.98;
}

.text-hero-title {
  font-size: var(--step-hero-title);
}

.text-h2 {
  font-size: var(--step-h2);
}

.text-h3 {
  font-size: var(--step-h3);
}

.text-price {
  font-size: var(--step-price);
  line-height: 0.9;
  letter-spacing: -0.04em;
}

.text-band {
  font-size: var(--step-band);
  font-weight: var(--weight-display);
  font-stretch: var(--wdth-label);
  line-height: 1.15;
  letter-spacing: -0.01em;
}

.text-lead {
  font-size: var(--step-lead);
  line-height: 1.5;
}

.text-body {
  font-size: var(--step-body);
}

.text-small {
  font-size: var(--step-small);
}

.measure {
  max-inline-size: 35rem;
}

/* ---------------------------------------------------------------- 4. Blocks */

/* Skip link: a solid, off-screen until it has focus. */
.skip-link {
  position: absolute;
  inset-block-start: 0.75rem;
  inset-inline-start: 0.75rem;
  z-index: 10;
  padding: 0.75rem 1.25rem;
  background-color: var(--ink);
  color: var(--paper);
  font-weight: var(--weight-label);
  font-stretch: var(--wdth-label);
  text-decoration-line: none;
  transform: translateY(-200%);
}

.skip-link:focus {
  transform: none;
}

/* Site header: wordmark or lockup on one side, nav on the other. */
.site-header {
  padding-block: 1.5rem;
}

.site-header__inner {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 0.5rem 2rem;
}

.wordmark {
  font-size: 1.125rem;
  font-weight: var(--weight-label);
  font-stretch: var(--wdth-display);
  letter-spacing: -0.01em;
  text-decoration-line: none;
}

.lockup {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.5rem 1rem;
}

/* The lockup's divider is a line, in the ink. */
.lockup__divider {
  inline-size: 2px;
  block-size: 1.5rem;
  background-color: currentColor;
}

.nav-link {
  display: inline-block;
  padding-block: 0.75rem;
  font-weight: var(--weight-ui);
}

/* Button: a solid with paper type knocked out. Hover and active draw a
   paper underline (the line tool) instead of shifting the ink. */
.button {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-block-size: var(--target-min);
  padding-inline: 1.25rem;
  border: 0;
  background-color: var(--ink);
  color: var(--paper);
  font-family: inherit;
  font-size: 1rem;
  font-weight: var(--weight-label);
  font-stretch: var(--wdth-label);
  line-height: 1.2;
  text-decoration-line: none;
  text-decoration-thickness: var(--rule);
  text-underline-offset: 0.25em;
  cursor: pointer;
  /* A <button> (the contact form's) stays a square solid on every engine. */
  border-radius: 0;
  appearance: none;
}

.button:hover,
.button[data-state="hover"] {
  text-decoration-line: underline;
}

.button:active,
.button[data-state="active"] {
  text-decoration-line: underline;
  text-decoration-thickness: calc(var(--rule) * 2);
  text-underline-offset: 0.15em;
}

.button--large {
  min-block-size: 3.75rem;
  padding-inline: 1.75rem;
  font-size: 1.1875rem;
}

/* Solid: an ink fill with paper type (S4). Focus rings inside it are paper. */
.solid {
  background-color: var(--ink);
  color: var(--paper);
}

.solid :focus-visible,
.solid [data-state="focus"] {
  outline-color: var(--paper);
}

/* Band: the page's one solid band; three short lines that stack on phone. */
.band__list {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
  padding: 1.75rem 0;
  list-style: none;
}

/* Steps: numbered rows between 1.5px rules (the line tool). */
.steps {
  padding: 0;
  list-style: none;
  border-block-end: var(--rule) solid;
}

.steps__item {
  display: grid;
  grid-template-columns: 3rem minmax(0, 1fr);
  gap: 1rem;
  padding-block: 1.5rem 1.75rem;
  border-block-start: var(--rule) solid;
}

.steps__number {
  font-size: 2rem;
  font-weight: var(--weight-display);
  font-stretch: var(--wdth-display);
  line-height: 1;
}

.steps__title {
  font-size: 1.25rem;
  font-weight: var(--weight-label);
  font-stretch: var(--wdth-label);
  line-height: 1.2;
  letter-spacing: 0;
}

/* What's in the site: items under 1.5px rules (the line tool), two columns
   from 40rem (copy deck §35). */
.features {
  display: grid;
  column-gap: clamp(2rem, 1.071rem + 3.810vw, 4.5rem);
  padding: 0;
  list-style: none;
  border-block-end: var(--rule) solid;
}

.features__item {
  padding-block: 1.5rem 1.75rem;
  border-block-start: var(--rule) solid;
}

.features__item > p {
  max-inline-size: 35rem;
}

.features__title,
.faq__question {
  font-size: 1.25rem;
  font-weight: var(--weight-label);
  font-stretch: var(--wdth-label);
  line-height: 1.2;
  letter-spacing: 0;
}

/* Questions: each answer under its question, between the rule list's rules. */
.faq > .faq__item {
  padding-block: 1.25rem 1.5rem;
}

/* Field: the title's generated art. A fixed-size box (never scaled: one
   grain is one CSS pixel) tinted with the ink through a 1-bit mask. Without
   mask support it paints nothing; it must never show as a solid rectangle. */
.field {
  position: absolute;
  pointer-events: none;
}

/* Below 64rem the grain field is 1024 wide, anchored to the right edge, so it
   bleeds off both edges at every width up to 1023px. Its right 390 columns
   are the phone board's cut, so a 390 screen shows exactly that; its left
   side fades in from nothing (RG2 R2, Mooie's 3d). */
.field--grain {
  inline-size: 1024px;
  block-size: 280px;
}

.field--kit,
.field--kit-closing {
  display: none;
}

.field--kit {
  inline-size: 880px;
  block-size: 740px;
}

.field--kit-closing {
  inline-size: 880px;
  block-size: 440px;
}

/* Below 64rem the image-led closing field is this 1024-wide preset, anchored
   to the right edge: it bleeds off both edges at every width up to 1023px,
   and its envelope fades the left side to nothing (no hard cut; RG2 R2). */
.field--kit-closing-phone {
  inline-size: 1024px;
  block-size: 240px;
}

@supports (mask-image: none) or (-webkit-mask-image: none) {
  .field {
    background-color: var(--ink);
    -webkit-mask-size: 100% 100%;
    mask-size: 100% 100%;
    -webkit-mask-repeat: no-repeat;
    mask-repeat: no-repeat;
  }

  .field--grain {
    -webkit-mask-image: url("../../fields/grain-field-phone.png?v=84d46ff35d");
    mask-image: url("../../fields/grain-field-phone.png?v=84d46ff35d");
  }

  .field--kit {
    -webkit-mask-image: url("../../fields/field-kit.png?v=49bb3f57cd");
    mask-image: url("../../fields/field-kit.png?v=49bb3f57cd");
  }

  .field--kit-closing {
    -webkit-mask-image: url("../../fields/field-kit-closing.png?v=85da2aaee1");
    mask-image: url("../../fields/field-kit-closing.png?v=85da2aaee1");
  }

  .field--kit-closing-phone {
    -webkit-mask-image: url("../../fields/field-kit-closing-phone.png?v=2b01594915");
    mask-image: url("../../fields/field-kit-closing-phone.png?v=2b01594915");
  }

  @media (min-width: 64rem) {
    .field--grain {
      -webkit-mask-image: url("../../fields/grain-field.png?v=f0d0d3fd67");
      mask-image: url("../../fields/grain-field.png?v=f0d0d3fd67");
    }
  }
}

/* The grain field swaps with the home's composition: the 1024 x 280 phone
   field under the copy below 64rem, the 900 x 900 field beside it from 64rem. */
@media (min-width: 64rem) {
  .field--grain {
    inline-size: 900px;
    block-size: 900px;
  }
}

/* Kit fields switch with the title page's composition, at 64rem like the
   home: below it the hero field is hidden and the closing field is the phone
   preset; from it, the 880-wide hero and closing fields sit beside the copy. */
@media (min-width: 64rem) {
  .field--kit,
  .field--kit-closing {
    display: block;
  }

  .field--kit-closing-phone {
    display: none;
  }
}

/* Plate: where an image goes. FPO until a real image is approved (PLAN §6):
   a 1.5px keyline, an X corner to corner, a paper-backed label. */
.plate__frame {
  position: relative;
  display: grid;
  place-items: center;
  padding: 1rem;
  aspect-ratio: 4 / 3;
  border: var(--rule) solid;
}

.plate__x {
  position: absolute;
  inset: 0;
  inline-size: 100%;
  block-size: 100%;
  stroke: currentColor;
  stroke-width: 1px;
}

.plate__label {
  position: relative;
  padding: 0.625rem 1rem;
  background-color: var(--paper);
  font-size: 1rem;
  font-weight: var(--weight-label);
  font-stretch: var(--wdth-label);
  line-height: 1.4;
  text-align: center;
}

.plate__img {
  inline-size: 100%;
  block-size: auto;
  aspect-ratio: 4 / 3;
  object-fit: cover;
}

.plate__caption {
  margin-block-start: 0.75rem;
  font-size: var(--step-small);
}

/* Site footer: plain, or solid (the image-led kit's closing). */
.site-footer {
  padding-block: 2rem 1.5rem;
  font-size: var(--step-small);
  font-weight: var(--weight-ui);
}

/* Title pages (PLAN-ng-site Chunk 3; boards "product page, field-led" and
   "image-led" at 1440). Phone: the lockup alone in the header (the nav and
   its button join from 40rem); one column until 64rem; the hero field hidden
   and the closing field on its phone preset below 64rem. */
.site-header.title-header {
  padding-block: clamp(1rem, 0.814rem + 0.762vw, 1.5rem);
}

.lockup__home {
  text-decoration-line: none;
}

.lockup__home:hover,
.lockup__home[data-state="hover"] {
  text-decoration-line: underline;
}

.title-nav {
  display: none;
  --cluster-space: 0.5rem 2.25rem;
}

.title-hero {
  position: relative;
  /* The field bleeds off the right edge; clip it so the page never scrolls sideways. */
  overflow-x: clip;
  /* 56 to 140 above (the boards' 140 at 1440), 48 to 80 below. */
  padding-block: clamp(3.5rem, 1.55rem + 8vw, 8.75rem) clamp(3rem, 2.257rem + 3.048vw, 5rem);
}

.title-hero__text {
  --stack-space: 2rem;
  align-items: flex-start;
}

.title-title {
  font-size: var(--step-hero-title);
}

.title-lead {
  max-inline-size: 35rem;
  font-size: var(--step-lead);
  line-height: 1.5;
}

/* The boards put the CTA row 8px further below the lead than the stack's gap
   (32 + 8). Added to the stack's own margin, not in place of it. */
.title-cta {
  --cluster-space: 1rem 1.75rem;
  margin-block-start: calc(var(--stack-space) + 0.5rem);
}

/* Where "Build my site" stands while the store is paused. */
.title-paused {
  font-weight: var(--weight-ui);
}

.price-note {
  display: flex;
  flex-direction: column;
  gap: 0.25rem;
}

.price-note__amount {
  font-size: 1.75rem;
  font-weight: var(--weight-display);
  font-stretch: var(--wdth-display);
  line-height: 1;
}

.price-note__text {
  font-size: var(--step-small);
  font-weight: var(--weight-ui);
}

/* The hero plate keeps paper around it (S6). */
.title-hero__plate {
  margin-block-start: var(--space-plate);
}

.title-section {
  padding-block-start: var(--space-section);
}

.title-section > .stack,
.title-section.stack {
  --stack-space: clamp(2rem, 1.629rem + 1.524vw, 3rem);
}

.split {
  display: grid;
  gap: clamp(2.5rem, 1.571rem + 3.810vw, 5rem);
  align-items: start;
}

.price-block__amount {
  font-size: var(--step-price);
  font-weight: var(--weight-display);
  font-stretch: var(--wdth-display);
  line-height: 0.9;
  letter-spacing: -0.04em;
}

.price-block__note {
  margin-block-start: 0.75rem;
  font-size: 1.375rem;
  font-weight: var(--weight-label);
  font-stretch: var(--wdth-label);
}

.pricing {
  --stack-space: 1.75rem;
  align-items: flex-start;
}

.pricing-head {
  font-size: var(--step-h3);
}

.pricing-lead {
  max-inline-size: 35rem;
  font-size: 1.1875rem;
}

/* Rows between 1.5px rules (the line tool). */
.rule-list {
  inline-size: 100%;
  border-block-end: var(--rule) solid;
}

.rule-list > * {
  padding-block: 1rem;
  border-block-start: var(--rule) solid;
}

/* Image-led closing: a ground plane whose field lands on the solid footer. */
.title-closing {
  position: relative;
  margin-block-start: var(--space-section);
}

.title-closing__text {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 0.25rem;
}

.title-closing__head {
  font-size: 1.75rem;
  font-weight: var(--weight-display);
  font-stretch: var(--wdth-display);
  line-height: 1.1;
  letter-spacing: -0.01em;
}

.title-closing__contact {
  font-size: 1.1875rem;
}

.title-closing__field {
  position: relative;
  block-size: 240px;
  margin-block-start: var(--space-plate);
  overflow-x: clip;
}

.title-closing__field .field {
  inset-block-end: 0;
  inset-inline-end: 0;
}

.title-footer {
  margin-block-start: var(--space-section);
}

.title-footer.solid {
  margin-block-start: 0;
  padding-block: 2rem 1.5rem;
}

.title-footer__lead {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 0.5rem 2rem;
  padding-block-start: 1rem;
  border-block-start: var(--rule) solid;
  font-size: var(--step-body);
  font-weight: var(--weight-body);
}

.title-footer.solid .title-footer__lead {
  padding-block-start: 0;
  border-block-start: 0;
}

/* The links are a cluster inside the row (inheriting its gap), so on a phone
   they wrap as a group under the copyright line, not one link at a time. */
.title-footer__row {
  --cluster-space: 0 2rem;
}

@media (min-width: 40rem) {
  .title-nav {
    display: flex;
  }
}

@media (min-width: 64rem) {
  /* Field-led: the hero is tall enough for the 880 x 740 field, which lands
     on the band (its box's bottom edge is the hero's). Its left edge is the
     board's (100% - 880px) or far enough right that no ink sits under the
     copy (S8): the H1's longest line ("your electrical") measures 8.43em,
     budgeted as 8.5em of --step-hero-title, and the mask's ink starts far
     enough in that 64px of the box may sit under that line's end; the 35rem
     lead sits lower, where only ~46px may (32px used). At 1440 that puts the
     box at x=680, not the board's 560: the board itself has sparse ink under
     its H1 (measured at Gate 3). */
  .title-hero[data-hero="field"] {
    min-block-size: 47.5rem;
  }

  .title-hero[data-hero="field"] .field--kit {
    inset-block-end: 0;
    inset-inline-start: max(
      calc(var(--space-gutter) + var(--step-hero-title) * 8.5 - 64px),
      calc(var(--space-gutter) + 35rem - 32px),
      calc(100% - 880px)
    );
  }

  /* Image-led, as its board: a 760-tall hero with no padding of its own, the
     copy and the plate side by side (about the board's 600 : 632) and
     centered in it. The H1 keeps the board's three lines (nowrap); the copy
     column is never narrower than that, so the H1 never runs into the gap or
     the plate (the board lets its 674px line overflow a 600px column), and
     the plate takes what's left. */
  .title-hero[data-hero="image"] {
    padding-block: 0;
  }

  .title-hero[data-hero="image"] .title-hero__grid {
    display: grid;
    grid-template-columns: minmax(min-content, 15fr) minmax(0, 16fr);
    gap: 5rem;
    align-items: center;
    min-block-size: 47.5rem;
  }

  .title-hero[data-hero="image"] .title-title {
    white-space: nowrap;
  }

  .title-hero[data-hero="image"] .title-hero__plate {
    margin-block-start: 0;
  }

  .split {
    grid-template-columns: minmax(0, 35rem) minmax(0, 1fr);
  }

  .pricing {
    padding-block-start: 1.25rem;
  }

  /* The closing plane is 440 tall; its field lands on the solid footer, clear
     of the closing copy, which sits at its bottom left. */
  .title-closing {
    display: flex;
    align-items: flex-end;
    min-block-size: 27.5rem;
    padding-block-end: 4rem;
  }

  .title-closing__field {
    position: absolute;
    inset: 0;
    z-index: -1;
    block-size: auto;
    margin: 0;
    overflow: clip;
    pointer-events: none;
  }

  .title-closing__field .field--kit-closing {
    inset-inline-end: auto;
    inset-inline-start: max(
      calc(var(--space-gutter) + 26.25rem + 40px - 40px),
      calc(100% - 880px)
    );
  }
}

/* Home: the studio's one-screen page (boards "B: One ink" at 1440 and 390).
   Below 64rem the phone field sits in flow under the copy, bleeding to both
   edges; from 64rem the 900 x 900 field sits beside the copy, flush to the
   page's top, bleeding off the right edge and clipped at the page's bottom. Its left edge is the
   board's (100% - 840px, x=600 at 1440) or, on narrower screens, far enough
   right that its art (which starts 100px into the mask) stays 40px clear of
   the text: the wider of the 31.25rem paragraph and the H1, whose longest
   line ("Software,") measures 5.85em, budgeted as 6em of --step-hero-home.
   No text sits on a field (S8). */
/* Two classes, so the home's padding (the boards': 24 to 44 above, none
   below) beats .site-header's own at every width, including its 40rem step
   further down this file (RULING-ng-site-gate2 R1). */
.site-header.home-header {
  padding-block: clamp(1.5rem, 1.036rem + 1.905vw, 2.75rem) 0;
}

.home-main {
  padding-block-start: clamp(5.5rem, 4.479rem + 4.190vw, 8.25rem);
}

.home-main > .stack {
  --stack-space: clamp(1.5rem, 1.221rem + 1.143vw, 2.25rem);
}

.home-title {
  font-size: var(--step-hero-home);
  line-height: 0.98;
}

.home-lead {
  max-inline-size: 31.25rem;
  font-size: var(--step-lead);
}

.home__field {
  position: relative;
  block-size: 280px;
  margin-block-start: 0.75rem;
  margin-inline: calc(-1 * var(--space-gutter));
  overflow-x: clip;
}

.home__field .field {
  inset-block-start: 0;
  inset-inline-end: 0;
}

.home-footer {
  padding-block: 0.25rem clamp(1.25rem, 0.879rem + 1.524vw, 2.25rem);
}

.home-footer__row {
  --cluster-space: 0 clamp(1.25rem, 0.971rem + 1.143vw, 2rem);
}

.home-footer__row .nav-link {
  padding-block: 0.75rem;
}

@media (min-width: 64rem) {
  /* The header keeps the height its "Contact us" link gave it (a nav link's
     line plus its 0.75rem padding each side), so moving the link into the
     hero moves nothing else (Mooie, 2026-11-06). */
  .home-header .site-header__inner {
    min-block-size: calc(1lh + 1.5rem);
  }

  /* Painted beneath the content (the paper is the canvas behind it), so no
     layer sits over the text: tools reading the background behind a word,
     such as axe's contrast check, see the paper. */
  .home__field {
    position: absolute;
    inset: 0;
    z-index: -1;
    block-size: auto;
    margin: 0;
    overflow: clip;
    pointer-events: none;
  }

  /* Flush to the page's top (Mooie, 2026-11-06); the boards' 90px gap is closed. */
  .home__field .field {
    inset-block-start: 0;
    inset-inline-end: auto;
    inset-inline-start: max(
      calc(var(--space-gutter) + max(31.25rem, var(--step-hero-home) * 6) + 40px - 100px),
      calc(100% - 840px)
    );
  }
}

/* Studio pages beyond home: the legal pages, the hosting guide, contact and
   the error pages (PLAN-ng-site D12, Chunk 5; templates/studio/page_base.html).
   No board draws these; they reuse the boards' header, rules and type roles.
   A reading column of running text, a form and an error page. */
.wordmark--link {
  display: inline-block;
  padding-block: 0.75rem;
}

.wordmark--link:hover,
.wordmark--link[data-state="hover"] {
  text-decoration-line: underline;
}

.page {
  padding-block-start: clamp(2rem, 1.257rem + 3.048vw, 4rem);
}

.page-footer {
  margin-block-start: var(--space-section);
}

.page-footer__row {
  --cluster-space: 0 2rem;
  justify-content: space-between;
  padding-block-start: 1rem;
  border-block-start: var(--rule) solid;
}

.page-footer__links {
  --cluster-space: 0 2rem;
}

/* Prose: a document's running text, styled through its plain markup, so a
   policy's pinned element stays bare HTML (tests/test_ng_policy_pins.py).
   Nothing here hides, reorders, transforms or adds text: what a buyer reads
   is what the pin hashes. */
.prose {
  max-inline-size: 35rem;
}

.prose > * + * {
  margin-block-start: 1em;
}

.prose h1 {
  font-size: var(--step-h2);
}

.prose > h1 + * {
  margin-block-start: clamp(1.25rem, 1.064rem + 0.762vw, 1.75rem);
}

/* Small heads: label weight and width (S7). */
.prose :is(h2, h3) {
  font-weight: var(--weight-label);
  font-stretch: var(--wdth-label);
  line-height: 1.2;
  letter-spacing: 0;
}

.prose h2 {
  margin-block-start: 2.5rem;
  font-size: 1.375rem;
}

.prose h3 {
  margin-block-start: 2rem;
  font-size: 1.1875rem;
}

.prose > :is(h2, h3) + * {
  margin-block-start: 0.75rem;
}

.prose :is(ul, ol) {
  padding-inline-start: 1.5em;
}

.prose li + li,
.prose li > :is(ul, ol) {
  margin-block-start: 0.375em;
}

/* The line tool between sections. Adjacent margins collapse, so a head after
   a rule sits 2.5rem below it, not 5rem. */
.prose > hr {
  margin-block: 2.5rem;
}

.prose blockquote {
  padding-inline-start: 1.25rem;
  border-inline-start: var(--rule) solid;
  font-weight: var(--weight-label);
  font-stretch: var(--wdth-label);
}

.prose strong {
  font-weight: var(--weight-label);
}

.prose > .rule-list {
  margin-block-start: 2.5rem;
}

/* A link standing on its own line gets a 44px target (PLAN §3). */
.link-block {
  display: inline-block;
  padding-block: 0.75rem;
}

/* A short label after a line of text: a keyline (the line tool), never a fill. */
.tag {
  display: inline-block;
  margin-inline-start: 0.5rem;
  padding-inline: 0.5rem;
  border: var(--rule) solid;
  font-size: var(--step-small);
  font-weight: var(--weight-label);
  font-stretch: var(--wdth-label);
  line-height: 1.6;
  white-space: nowrap;
}

/* Form: labels over controls, ruled in the ink on paper. No class here is
   named "field": .field is the generated art (section 4, Fields). The gap,
   not .stack's margins, spaces it, so the hidden inputs push nothing. */
.form {
  display: flex;
  flex-direction: column;
  gap: 1.5rem;
  max-inline-size: 30rem;
}

.form > .button {
  align-self: flex-start;
}

.form__group {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
}

.form__label {
  font-weight: var(--weight-label);
  font-stretch: var(--wdth-label);
}

.form__control {
  display: block;
  inline-size: 100%;
  min-block-size: var(--target-min);
  padding: 0.625rem 0.75rem;
  border: var(--rule) solid;
  border-radius: 0;
  background-color: var(--paper);
  color: inherit;
  font: inherit;
  appearance: none;
}

textarea.form__control {
  min-block-size: 8rem;
  resize: vertical;
}

/* A placeholder in the ink at full strength (no tint, S2), set light so it
   doesn't read as text someone typed. */
.form__control::placeholder {
  color: currentColor;
  opacity: 1;
  font-weight: 300;
}

/* Autofill: the engines' tinted fills can't be overridden with a background,
   so paper is painted over them from inside. */
.form__control:autofill,
.form__control:-webkit-autofill {
  box-shadow: inset 0 0 0 100vmax var(--paper);
  -webkit-text-fill-color: var(--ink);
}

.form__control:user-invalid {
  box-shadow: none;
}

.form__control:hover,
.form__control[data-state="hover"] {
  border-width: calc(var(--rule) * 2);
  padding: calc(0.625rem - var(--rule)) calc(0.75rem - var(--rule));
}

/* An error: a keyline box, label weight (the line tool). */
.form__error {
  padding: 0.75rem 1rem;
  border: var(--rule) solid;
  font-weight: var(--weight-label);
  font-stretch: var(--wdth-label);
}

/* Turnstile's widget is 65px tall; reserve it so the button doesn't move. */
.cf-turnstile {
  min-block-size: 65px;
}

.error-page {
  --stack-space: 1.5rem;
  align-items: flex-start;
}

.error-page__code {
  font-size: var(--step-hero-title);
}

/* The purchase path's pages (PLAN-purchase-path §2.2): checkout's refusals and
   success, sign-in and the account. Their stacks hold a button, which keeps
   its own width, and a rule, which runs the stack's width. */
.purchase-flow {
  align-items: flex-start;
}

.purchase-flow > hr,
.purchase-flow > .rule-list {
  align-self: stretch;
}

/* The lists are ruled, not bulleted. */
.purchase-flow > .rule-list,
.account-orders {
  padding-inline-start: 0;
  list-style: none;
}

.account-head,
.account-order__top {
  justify-content: space-between;
}

.account-head {
  align-items: baseline;
}

/* The order's row spans its item, so the tag sits at the end: the item's
   stack aligns its children to the start. */
.account-order__top {
  align-self: stretch;
  align-items: flex-start;
}

.account-orders > li {
  align-items: flex-start;
}

.account-empty {
  padding-block: 3rem;
  border: var(--rule) dashed;
  text-align: center;
}

/* The download (PLAN-purchase-path Chunk 2): its notices in a keyline box,
   across the stack, and the order's details as label-over-value rows. */
.download-notice {
  align-self: stretch;
  padding: 1rem;
  border: var(--rule) solid;
}

.download-notice__list {
  padding-inline-start: 1.25rem;
}

.download-info dd {
  overflow-wrap: anywhere;
}

.download-info dd + dt {
  margin-block-start: 1rem;
}

/* ----------------------------------------------------------- 5. Exceptions */

.stack[data-space="xs"] {
  --stack-space: 0.5rem;
}

.stack[data-space="s"] {
  --stack-space: 1rem;
}

.stack[data-space="l"] {
  --stack-space: 2.25rem;
}

.stack[data-space="xl"] {
  --stack-space: 3rem;
}

.plate[data-ratio="3/2"] :is(.plate__frame, .plate__img) {
  aspect-ratio: 3 / 2;
}

.plate[data-ratio="16/9"] :is(.plate__frame, .plate__img) {
  aspect-ratio: 16 / 9;
}

.plate[data-ratio="1/1"] :is(.plate__frame, .plate__img) {
  aspect-ratio: 1 / 1;
}

/* ------------------------------------------------------- Wider than phone */

@media (min-width: 40rem) {
  .site-header {
    padding-block: 2rem;
  }

  .wordmark {
    font-size: 1.25rem;
  }

  .steps__item {
    grid-template-columns: 4rem minmax(0, 1fr);
  }

  .steps__number {
    font-size: 2.5rem;
  }

  .steps__title {
    font-size: 1.375rem;
  }

  .features {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  .features__title,
  .faq__question {
    font-size: 1.375rem;
  }
}

@media (min-width: 64rem) {
  .band__list {
    flex-direction: row;
    flex-wrap: wrap;
    justify-content: space-between;
    gap: 0.5rem 2rem;
    padding-block: 2.5rem;
  }
}

/* ------------------------------------------------------------------ Motion */

/* Entrances (PLAN-ng-site §4, MV1 to MV7; RSSM). The template marks what may
   move ([data-enter]); motion.js sets the hook ([data-entrance]) once, as a
   marked element first enters the screen, and sets it to "done" when the
   entrance ends. Everything that changes over time is in this one block, so
   with reduced motion, in print, or with the script off, refused or not yet
   run, nothing moves and every element is in place at full ink (MV1, MV2).
   - Translate and opacity only, so nothing shifts or changes size (MV4).
   - One play, to an explicit end at full ink and no offset, within one
     second, delay included (MV3; S2: an entrance may fade).
   - "done" takes the animation off, so nothing replays when the layout or
     the visitor's preference changes later (MV3). */
@media screen and (prefers-reduced-motion: no-preference) {
  [data-enter][data-entrance="play"] {
    animation-name: ng-enter;
    animation-duration: 800ms;
    animation-timing-function: cubic-bezier(0.2, 0.7, 0.2, 1);
    animation-fill-mode: both;
  }

  /* The second column's items follow the first's by a beat. */
  [data-enter="2"][data-entrance="play"] {
    animation-delay: 90ms;
  }

  [data-enter][data-entrance="done"] {
    animation-name: none;
  }

  @keyframes ng-enter {
    from {
      opacity: 0;
      translate: 0 1.25rem;
    }

    to {
      opacity: 1;
      translate: none;
    }
  }
}
