/* ==========================================================================
   JANARIX — THE PRODUCTION LAYER
   Loaded fourth and last, after janarix-responsive.css.

   WHY THIS IS A SEPARATE FILE

   Everything in here exists for a measured reason: a contrast ratio, a
   layout-shift score, or a page that did not exist before. None of it is
   a design decision, and none of it belongs in the three files that
   describe how the site looks and behaves.

   Keeping it apart means two things. You can read the whole production
   hardening in one sitting, and you can delete any single rule — or this
   entire file and its four <link> lines — without unpicking anything
   else. The site then returns to exactly what it was.

   It loads last so that it wins the cascade without needing !important
   anywhere. There is not one in this file.

   CONTENTS

   1   Hero legibility     text over photographs, measured
   2   Layout shift        space reserved for what JavaScript fills in
   3   The legal row       privacy and terms, in the footer
   4   Legal pages         privacy policy, terms, 404
   5   The visit strip     photographs on the Marstek page
   ========================================================================== */


/* ==========================================================================
   1. HERO LEGIBILITY

   Measured by removing the text's own ink, screenshotting what sits
   behind it, and comparing the lightest backdrop pixel against the type
   colour. Measured on the DAY frame of the cycle, which is the bright one
   and therefore the worst case.

   Eleven samples across the site failed WCAG AA. The home page was the
   worst: white display type at 1.49:1 where the standard asks for 3:1,
   sitting directly on the sun glare in the photograph, and the lead
   paragraph at 2.05:1 where it asks for 4.5:1.

   THE FIX IS NOT A DARKER PICTURE. Each gradient holds its dark side
   further across before releasing, so the words gain a backdrop and the
   part of the photograph you are meant to look at — the roof, the panels,
   the sky on the right — is untouched.
   ========================================================================== */

.hero-scrim.is-day {
  background:
    linear-gradient(97deg,
      rgba(12,18,26,.95) 0%,  rgba(13,19,27,.93) 24%, rgba(15,21,29,.86) 40%,
      rgba(18,24,30,.70) 54%, rgba(24,26,28,.40) 66%, rgba(30,28,24,.12) 78%,
      rgba(30,28,24,.00) 88%, rgba(30,28,24,.00) 100%),
    linear-gradient(180deg, rgba(10,16,26,.56) 0%, rgba(10,16,26,.12) 20%, transparent 42%);
}

.hero-scrim.is-night {
  background:
    linear-gradient(97deg,
      rgba(3,10,26,.96) 0%,  rgba(4,13,34,.94) 24%, rgba(5,17,45,.84) 40%,
      rgba(6,21,54,.64) 54%, rgba(7,24,60,.40) 66%, rgba(7,24,60,.24) 78%,
      rgba(7,24,60,.20) 100%),
    linear-gradient(180deg, rgba(3,10,26,.64) 0%, rgba(3,10,26,.18) 20%, transparent 42%);
}

/* The two heroes that use their own gradient rather than the day/night
   pair: the thank-you page and the Marstek page. Measured at 3.2:1 and
   4.15:1 on their lead paragraphs. */

.hero-scrim.is-daylight {
  background:
    linear-gradient(100deg,
      rgba(6,16,32,.94) 0%,  rgba(7,18,36,.90) 30%, rgba(9,22,44,.74) 50%,
      rgba(10,24,48,.44) 68%, rgba(10,24,48,.16) 84%, transparent 100%),
    linear-gradient(180deg, rgba(5,14,28,.62) 0%, rgba(5,14,28,.10) 34%, rgba(5,14,28,.46) 100%);
}

.hero-scrim.is-still {
  background:
    linear-gradient(97deg,
      rgba(3,10,26,.95) 0%,  rgba(4,13,34,.92) 26%, rgba(5,17,45,.78) 46%,
      rgba(6,20,52,.52) 64%, rgba(6,21,54,.26) 80%, rgba(7,24,60,.14) 100%),
    linear-gradient(180deg, rgba(3,10,26,.58) 0%, rgba(3,10,26,.10) 32%, rgba(3,10,26,.34) 100%);
}

/* The endurance line sits low in the hero, below the point where the
   gradient above has already released. Its labels measured 1.87:1. This
   lays a soft floor under the bottom of the hero only; the picture above
   it is unchanged. */
.hero::after {
  content: '';
  position: absolute; inset: auto 0 0 0; height: 46%;
  background: linear-gradient(180deg,
    rgba(8,14,24,0) 0%, rgba(8,14,24,.42) 52%, rgba(8,14,24,.66) 100%);
  pointer-events: none;
  z-index: 1;
}
.hero-inner { position: relative; z-index: 2; }

/* The endurance caption is the most muted tone the palette has for dark
   surfaces. At 12px uppercase it needs 4.5:1 and measured 3.64:1. In the
   hero only, it steps up one tone. Everywhere else it is unchanged. */
.hero .hero-endur-head .k { color: var(--on-night-2); }

@media (max-width: 780px) {
  /* On a phone the gradients run vertically instead, so the same
     correction is applied along that axis. */
  .hero-scrim.is-day {
    background: linear-gradient(180deg,
      rgba(12,18,26,.94) 0%,  rgba(13,19,27,.90) 38%,
      rgba(18,22,28,.66) 58%, rgba(22,24,26,.48) 74%, rgba(18,19,22,.62) 100%);
  }
  .hero-scrim.is-night {
    background: linear-gradient(180deg,
      rgba(3,10,26,.95) 0%,  rgba(4,13,34,.92) 38%,
      rgba(5,17,45,.70) 58%, rgba(6,21,54,.52) 74%, rgba(5,15,40,.68) 100%);
  }
  .hero-scrim.is-daylight {
    background: linear-gradient(180deg,
      rgba(6,16,32,.92) 0%, rgba(7,18,36,.86) 28%,
      rgba(8,20,40,.84) 56%, rgba(6,16,32,.92) 100%);
  }
  .hero-scrim.is-still {
    background: linear-gradient(180deg,
      rgba(3,10,26,.93) 0%, rgba(4,13,34,.86) 30%,
      rgba(5,17,45,.78) 58%, rgba(4,12,30,.88) 100%);
  }
  .hero::after { height: 54%; }
}


/* ==========================================================================
   2. LAYOUT SHIFT

   These containers are empty in the HTML and filled by JavaScript after
   the page has already been painted. Each one was pushing the call to
   action and the footer down the page a moment after the reader's eyes
   had settled.

   Measured before: the product page 0.723, the blog 0.267, the catalogue
   0.198, the projects page 0.156, the home page 0.119. Google treats
   anything above 0.1 as needing work and above 0.25 as poor.

   Reserving the space they are about to occupy removes the jump. None of
   these values changes where anything ends up; they only stop the gap
   collapsing before the content lands in it.
   ========================================================================== */

.endur { min-height: 47px; }
.hero-endur .endur { min-height: 67px; }   /* the labelled 24-hour variant */

#item        { min-height: 78vh; }
#postBody,
#projectBody { min-height: 60vh; }
#journalList { min-height: 60vh; }
#projectList { min-height: 340px; }
.prod-grid   { min-height: 70vh; }

/* The last shift on the home page, and the largest single one on the
   site at 0.119.

   js/sections.js hides switched-off bands with a stylesheet before the
   first paint, then removes them from the document afterwards. Hiding a
   node does not change which element is next to which; removing it does.
   So the ":has(+ .dawn-break)" rule in janarix.css is false when the page
   is painted and true a moment later, and the hero's bottom padding drops
   from 56px to about 29px at around 230ms, pulling the whole page up.

   On the home page the settled value is the tightened one, so applying it
   from the start renders identically and simply stops the jump. No other
   page is affected. */
body[data-page="index"] .hero .hero-inner {
  padding-bottom: clamp(28px, 3.5vh, 52px);
}


/* ==========================================================================
   3. THE LEGAL ROW

   Privacy policy and terms, above the copyright line, on every page. The
   markup lives in components/footer.html so it is written once.

   janarix-responsive.css already gives ".foot-legal a" its phone padding.
   This adds the row's own layout, and carries the same 24px target height
   up to desktop widths, where the links were 18px tall against the 24px
   minimum in WCAG 2.2.
   ========================================================================== */

.foot-legal {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px 20px;
  padding: 18px 0;
}
.foot-legal a {
  font-size: 12px;
  color: var(--on-night-3);
  text-decoration: none;
  min-height: 24px;
  display: inline-flex;
  align-items: center;
  transition: color var(--t-fast) var(--ease);
}
.foot-legal a:hover {
  color: var(--on-night);
  text-decoration: underline;
  text-underline-offset: 4px;
  text-decoration-color: var(--volt);
}
.foot-legal .sep {
  color: var(--on-night-3);
  opacity: .5;
  font-size: 12px;
}

@media (max-width: 560px) {
  .foot-legal { gap: 6px 14px; }
  .foot-legal .sep { display: none; }
}


/* ==========================================================================
   4. LEGAL PAGES

   Long-form text, which the site had no pattern for. Built from the type
   scale and the rules already in use, so the privacy policy and the terms
   sit inside the existing design rather than beside it.
   ========================================================================== */

.legal { max-width: 74ch; }

.legal h2 {
  font-size: clamp(1.25rem, 2.4vw, 1.5rem);
  margin-top: 44px;
  margin-bottom: 12px;
  scroll-margin-top: 110px;   /* so the sticky header does not cover a jump */
}
.legal h2:first-of-type { margin-top: 0; }

.legal h3 {
  font-size: 1.0625rem;
  margin-top: 26px;
  margin-bottom: 8px;
  font-family: var(--body);
  font-weight: 600;
}

.legal p,
.legal li {
  font-size: var(--fs-sm);
  line-height: 1.75;
  color: var(--ink-2);
}
.legal p + p { margin-top: 14px; }

.legal ul,
.legal ol {
  margin: 12px 0 0 0;
  padding-left: 22px;
  display: grid;
  gap: 8px;
}
.legal li::marker { color: var(--volt-deep); }

.legal a {
  color: var(--ink);
  text-decoration: underline;
  text-underline-offset: 3px;
  text-decoration-color: var(--volt);
}

.legal .updated {
  font-size: var(--fs-xs);
  color: var(--ink-3);
  padding-bottom: 22px;
  margin-bottom: 34px;
  border-bottom: 1px solid var(--rule-day);
}

.legal-toc {
  display: flex;
  flex-wrap: wrap;
  gap: 8px 10px;
  margin-bottom: 40px;
  padding-bottom: 30px;
  border-bottom: 1px solid var(--rule-day);
}
.legal-toc a {
  font-size: var(--fs-xs);
  font-weight: 600;
  padding: 7px 13px;
  min-height: 32px;
  display: inline-flex;
  align-items: center;
  border-radius: var(--r-pill);
  text-decoration: none;
  background: var(--day-100);
  color: var(--ink-2);
  transition: background var(--t-fast) var(--ease), color var(--t-fast) var(--ease);
}
.legal-toc a:hover {
  background: var(--day-200);
  color: var(--ink);
}

/* The 404's list of destinations. Uses the button row that already
   exists; this only stops it running edge to edge on a wide screen. */
.notfound-links { max-width: 58ch; margin-inline: auto; }


/* ==========================================================================
   5. THE VISIT STRIP

   The photographs from the Marstek production tour, on marstek.html.

   The point of this rule is that the number of pictures is not baked into
   anything. auto-fit means the row decides for itself: one photograph
   fills the width, two sit side by side, three go three across, four wrap
   to a square. Adding a fourth or a fifth is a copy-paste in the HTML and
   nothing here changes.

   min(100%, 260px) rather than a plain 260px is what stops a single
   column being wider than the screen on a narrow phone, which is the
   usual way an auto-fit grid causes sideways scrolling.

   On a phone the photographs stack, which is deliberate. They are
   supporting evidence for the section, not the subject of it, and a
   group photograph shrunk to half of a 390px screen shows nothing.
   ========================================================================== */

.visit-shots {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 260px), 1fr));
  gap: clamp(14px, 1.8vw, 22px);
  align-items: start;
}
