/*
Theme Name: NZP Theme
Theme URI: https://n-z-p.com
Author: Net Zero Properties
Author URI: https://n-z-p.com
Description: Custom WordPress theme for Net Zero Properties S.à r.l. — a Luxembourg-domiciled holding company specialising in income-generating German residential real estate. Ships in English and German with its own language switcher, so no translation plugin is needed or wanted. Works with free plugins only, and renders completely with built-in defaults so nothing is required on activation.
Version: 1.1.0
Requires at least: 6.0
Tested up to: 7.1
Requires PHP: 7.4
License: GNU General Public License v2 or later
License URI: https://www.gnu.org/licenses/gpl-2.0.html
Text Domain: nzp-theme
Tags: business, real-estate, custom-logo, custom-menu, translation-ready, two-columns, right-sidebar
*/

/* ==========================================================================
   TABLE OF CONTENTS
   --------------------------------------------------------------------------
   01. Design tokens (custom properties)
   02. Reset and base
   03. Typography
   04. Layout: containers, sections, grids
   05. Buttons and links
   06. Placeholder system (TBD, missing images, missing docs)
   07. Site header and navigation
   08. Hero
   09. KPI cards
   10. Content cards and feature blocks
   11. Maps (office map, Germany region map)
   12. Timeline (Track Record)
   13. SDG cards (ESG Framework)
   14. Manage-to-Green (two-phase illustration and steps)
   15. Investors (login gate, partner carousel)
   16. Press cards
   17. Contact
   18. Blog: index, single, archive, pagination, comments
   19. 404
   20. Site footer
   21. Accessibility helpers
   22. Responsive (<= 768px)
   23. Print
   ========================================================================== */


/* ==========================================================================
   01. DESIGN TOKENS
   --------------------------------------------------------------------------
   The colour palette is carried over verbatim from the previous NZP site so
   the brand identity is unchanged. Two corrections were made deliberately:

   - The old `theme-secondary-50` token held a 20% alpha value despite its
     name. It is named `--color-secondary-20` here to match what it does.
   - The old `theme-light` (#F3F3F3) was declared but never used. It is now
     `--color-bg-alt` and drives every alternating section background.

   Social icons are also unified: the old theme's SVG icons were hardcoded
   to #CEA690 while the brand token was #DBAE95. Everything now uses the
   single `--color-secondary` value below.
   ========================================================================== */

:root {
  /* --- Brand palette ------------------------------------------------- */
  --color-primary:       #061F11; /* Deep brand green. Header, footer, hero. */
  --color-primary-90:    #384D3D; /* Lighter green used for hover states.    */
  --color-secondary:     #DBAE95; /* Warm sand. Accents, links, CTAs.        */
  --color-secondary-20:  rgba(219, 174, 149, 0.2); /* 20% sand wash.         */
  --color-white-20:      rgba(255, 255, 255, 0.2); /* 20% white overlay.     */
  --color-green-light:   #6E9678; /* Region / data-viz accent.               */
  --color-green-accent:  #2C7A4B; /* Readable green for emphasised words.    */
  --color-gold-dark:     #9A8074; /* Region / data-viz accent.               */
  --color-light-dark:    #E7EAEC; /* Cool grey. Borders, placeholders.       */

  /* --- Manage-to-Green: one colour per Phase 2 upgrade ------------------
     Each colour is used on BOTH the element drawn on the building and the
     bullet marker beside its description, so the reader can connect the
     two at a glance. */
  --color-heatpump: #2F7F8C; /* Teal   — heat pump system.        */
  --color-pv:       #3F7E44; /* Green  — photovoltaic generation. */
  --color-control:  #E8B517; /* Yellow — heating control system, matching
                                the yellow pipe runs on the building.  */
  --color-envelope: #9A8074; /* Brown  — envelope and insulation. */

  /* --- Surfaces and text --------------------------------------------- */
  --color-bg:            #FFFFFF;
  --color-bg-alt:        #F3F3F3; /* Alternating section background.         */
  --color-text:          #1A2620;
  --color-text-muted:    #5E6B64;
  --color-text-invert:   #FFFFFF;
  --color-border:        #E2E6E4;

  /* --- Typography ----------------------------------------------------- */
  --font-sans:    'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
  --font-display: 'Archivo', 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;

  --fs-xs:   0.75rem;   /* 12px */
  --fs-sm:   0.875rem;  /* 14px */
  --fs-base: 1rem;      /* 16px */
  --fs-md:   1.125rem;  /* 18px */
  --fs-lg:   1.375rem;  /* 22px */
  --fs-xl:   1.75rem;   /* 28px */
  --fs-2xl:  2.25rem;   /* 36px */
  --fs-3xl:  3rem;      /* 48px */

  /* --- Spacing scale --------------------------------------------------- */
  --space-1:  0.25rem;
  --space-2:  0.5rem;
  --space-3:  0.75rem;
  --space-4:  1rem;
  --space-5:  1.5rem;
  --space-6:  2rem;
  --space-7:  3rem;
  --space-8:  4rem;
  --space-9:  6rem;

  /* --- Layout ---------------------------------------------------------- */
  --container-max: 1180px; /* Standard content container.                    */
  --container-nar: 800px;  /* Narrow column for page.php.                    */
  --container-read: 740px; /* Reading measure for single.php.                */

  /* Header height is defined ONCE and reused for the body offset. In the
     previous theme the header was 72px but the spacer below it was 64px,
     so content sat 8px underneath the fixed bar. Deriving both from this
     single token makes that class of bug impossible. */
  --header-h:      72px;
  --header-h-mob:  64px;

  --radius:     4px;
  --radius-lg:  8px;
  --shadow-sm:  0 1px 2px rgba(6, 31, 17, 0.06);
  --shadow:     0 2px 8px rgba(6, 31, 17, 0.08);
  --shadow-lg:  0 8px 28px rgba(6, 31, 17, 0.12);
  --transition: 180ms ease;

  --z-header:   1000;
  --z-dropdown: 1010;
}


/* ==========================================================================
   02. RESET AND BASE
   ========================================================================== */

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

html {
  scroll-behavior: smooth;
  /* Anchor links must clear the fixed header. */
  scroll-padding-top: calc(var(--header-h) + var(--space-4));
}

body {
  margin: 0;
  font-family: var(--font-sans);
  font-size: var(--fs-base);
  line-height: 1.65;
  color: var(--color-text);
  background: var(--color-bg);
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  overflow-x: hidden;
}

/* The header is fixed, so push all page content clear of it. */
.nzp-site-content { padding-top: var(--header-h); }

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

/* WordPress core alignment classes for embedded/uploaded media. */
.alignleft  { float: left;  margin: 0 var(--space-5) var(--space-4) 0; }
.alignright { float: right; margin: 0 0 var(--space-4) var(--space-5); }
.aligncenter { display: block; margin-left: auto; margin-right: auto; }
.alignwide, .alignfull { margin-left: 0; margin-right: 0; }
.wp-caption { max-width: 100%; }
.wp-caption-text,
figcaption {
  font-size: var(--fs-sm);
  color: var(--color-text-muted);
  font-style: italic;
  margin-top: var(--space-2);
}

table { border-collapse: collapse; width: 100%; }
th, td {
  text-align: left;
  padding: var(--space-3);
  border-bottom: 1px solid var(--color-border);
}


/* ==========================================================================
   03. TYPOGRAPHY
   --------------------------------------------------------------------------
   Inter carries the interface and body copy. Playfair Display is reserved for
   display headings, preserving the serif/sans contrast of the original site.
   ========================================================================== */

h1, h2, h3, h4, h5, h6 {
  margin: 0 0 var(--space-4);
  font-weight: 600;
  line-height: 1.2;
  color: var(--color-primary);
}

h1 { font-family: var(--font-display); font-size: var(--fs-3xl); font-weight: 400; }
h2 { font-family: var(--font-display); font-size: var(--fs-2xl); font-weight: 400; }
h3 { font-size: var(--fs-xl); }
h4 { font-size: var(--fs-lg); }
h5 { font-size: var(--fs-md); }
h6 { font-size: var(--fs-base); text-transform: uppercase; letter-spacing: 0.06em; }

p { margin: 0 0 var(--space-4); }
p:last-child { margin-bottom: 0; }

ul, ol { margin: 0 0 var(--space-4); padding-left: var(--space-5); }
li { margin-bottom: var(--space-2); }

blockquote {
  margin: var(--space-6) 0;
  padding: var(--space-4) var(--space-5);
  border-left: 3px solid var(--color-secondary);
  background: var(--color-bg-alt);
  font-style: italic;
  color: var(--color-text-muted);
}

code, pre {
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 0.9em;
}
pre {
  background: var(--color-bg-alt);
  padding: var(--space-4);
  border-radius: var(--radius);
  overflow-x: auto;
}

/* Small uppercase label used above headings throughout the site. */
.nzp-eyebrow {
  display: block;
  font-size: var(--fs-xs);
  font-weight: 600;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--color-secondary);
  margin-bottom: var(--space-3);
}

/* Short sand rule used as a section divider. */
.nzp-rule {
  width: 48px;
  height: 2px;
  background: var(--color-secondary);
  border: 0;
  margin: var(--space-4) 0 var(--space-5);
}
.nzp-rule--center { margin-left: auto; margin-right: auto; }

/*
 * Body copy is deliberately uniform.
 *
 * `.nzp-lead` previously rendered larger and lighter than the paragraphs
 * following it, which made the first paragraph of a section look like a
 * different typeface. It is now identical to a normal paragraph, so any
 * remaining usage anywhere in the theme stays visually consistent.
 */
.nzp-lead {
  font-size: var(--fs-base);
  font-weight: 400;
  color: var(--color-text);
  line-height: 1.65;
}


/* ==========================================================================
   04. LAYOUT
   ========================================================================== */

/* One container class used by every template. In the previous theme two
   elements lost their desktop padding because the utility-class prefix was
   mistyped; a single shared class removes that failure mode entirely. */
.nzp-container {
  width: 100%;
  max-width: var(--container-max);
  margin-left: auto;
  margin-right: auto;
  padding-left: var(--space-4);
  padding-right: var(--space-4);
}

@media (min-width: 769px) {
  .nzp-container { padding-left: var(--space-6); padding-right: var(--space-6); }
}

.nzp-container--narrow  { max-width: var(--container-nar); }
.nzp-container--reading { max-width: var(--container-read); }

.nzp-section { padding-top: var(--space-8); padding-bottom: var(--space-8); }
.nzp-section--tight { padding-top: var(--space-7); padding-bottom: var(--space-7); }
.nzp-section--alt   { background: var(--color-bg-alt); }
.nzp-section--dark  { background: var(--color-primary); color: var(--color-text-invert); }
.nzp-section--dark h1,
.nzp-section--dark h2,
.nzp-section--dark h3,
.nzp-section--dark h4 { color: var(--color-text-invert); }

.nzp-section-head { max-width: 720px; margin-bottom: var(--space-7); }
.nzp-section-head--center { margin-left: auto; margin-right: auto; text-align: center; }

/* Generic responsive grid. Column count collapses to 1 under 768px. */
.nzp-grid { display: grid; gap: var(--space-5); }
.nzp-grid--2 { grid-template-columns: repeat(2, 1fr); }
.nzp-grid--3 { grid-template-columns: repeat(3, 1fr); }
.nzp-grid--4 { grid-template-columns: repeat(4, 1fr); }

/* Page hero used by all interior page templates. */
.nzp-page-header {
  background: var(--color-primary);
  color: var(--color-text-invert);
  padding: var(--space-8) 0;
  text-align: center;
}
.nzp-page-header h1 { color: var(--color-text-invert); margin-bottom: var(--space-3); }
.nzp-page-header p  { color: var(--color-secondary); max-width: 640px; margin: 0 auto; }


/* ==========================================================================
   05. BUTTONS AND LINKS
   ========================================================================== */

a {
  color: var(--color-primary);
  text-decoration-color: var(--color-secondary);
  text-underline-offset: 3px;
  transition: color var(--transition);
}
a:hover { color: var(--color-primary-90); }

.nzp-btn {
  display: inline-block;
  padding: var(--space-3) var(--space-6);
  font-size: var(--fs-base);
  font-weight: 600;
  font-family: var(--font-sans);
  text-align: center;
  text-decoration: none;
  border: 1px solid transparent;
  border-radius: var(--radius);
  cursor: pointer;
  transition: background var(--transition), color var(--transition), border-color var(--transition);
}

.nzp-btn--primary {
  background: var(--color-secondary);
  color: var(--color-primary);
}
.nzp-btn--primary:hover {
  background: #C9997F;
  color: var(--color-primary);
}

.nzp-btn--dark {
  background: var(--color-primary);
  color: var(--color-text-invert);
}
.nzp-btn--dark:hover { background: var(--color-primary-90); color: var(--color-text-invert); }

.nzp-btn--outline {
  background: transparent;
  color: var(--color-primary);
  border-color: var(--color-primary);
}
.nzp-btn--outline:hover { background: var(--color-primary); color: var(--color-text-invert); }

/* Outline button on a dark background. */
.nzp-btn--ghost {
  background: transparent;
  color: var(--color-text-invert);
  border-color: var(--color-white-20);
}
.nzp-btn--ghost:hover { background: var(--color-white-20); color: var(--color-text-invert); }

.nzp-btn--block { display: block; width: 100%; }

/* Inline "Read more →" style link. */
.nzp-link-arrow {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  font-weight: 600;
  font-size: var(--fs-sm);
  color: var(--color-primary);
  text-decoration: none;
}
.nzp-link-arrow::after {
  content: '\2192';
  transition: transform var(--transition);
}
.nzp-link-arrow:hover::after { transform: translateX(4px); }


/* ==========================================================================
   06. PLACEHOLDER SYSTEM
   --------------------------------------------------------------------------
   This site is being built ahead of final content sign-off. Every unresolved
   value renders as a deliberate, styled placeholder — never a blank space,
   a zero, or a broken asset. Each placeholder is muted but legible so the
   page reads as "in progress", not "broken".
   ========================================================================== */

/* Inline "TBD" marker, e.g. inside a KPI card. */
.nzp-tbd {
  color: var(--color-text-muted);
  font-weight: 500;
  font-style: normal;
}

/* Longer qualifier, e.g. "TBD - subject to internal approval". */
.nzp-tbd-note {
  display: inline-block;
  font-size: var(--fs-sm);
  color: var(--color-text-muted);
  background: var(--color-secondary-20);
  border-left: 2px solid var(--color-secondary);
  padding: var(--space-2) var(--space-3);
  border-radius: 0 var(--radius) var(--radius) 0;
}

/* Block-level placeholder panel for missing documents, graphics, video. */
.nzp-placeholder {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: var(--space-3);
  min-height: 200px;
  padding: var(--space-6);
  text-align: center;
  color: var(--color-text-muted);
  background: var(--color-light-dark);
  border: 2px dashed var(--color-secondary);
  border-radius: var(--radius);
}
.nzp-placeholder__title {
  font-weight: 600;
  font-size: var(--fs-md);
  color: var(--color-text-muted);
  margin: 0;
}
.nzp-placeholder__text {
  font-size: var(--fs-sm);
  margin: 0;
  max-width: 44ch;
}
.nzp-placeholder--sm { min-height: 120px; padding: var(--space-5); }
.nzp-placeholder--video { min-height: 320px; background: var(--color-primary); border-color: var(--color-white-20); }
.nzp-placeholder--video .nzp-placeholder__title,
.nzp-placeholder--video .nzp-placeholder__text { color: rgba(255, 255, 255, 0.75); }

/* Play-button glyph for the missing-video placeholder. */
.nzp-placeholder__play {
  width: 64px;
  height: 64px;
  border-radius: 50%;
  border: 2px solid var(--color-secondary);
  display: flex;
  align-items: center;
  justify-content: center;
}
.nzp-placeholder__play::after {
  content: '';
  border-style: solid;
  border-width: 11px 0 11px 18px;
  border-color: transparent transparent transparent var(--color-secondary);
  margin-left: 5px;
}

/* --------------------------------------------------------------------------
   Property photography
   Used sparingly as supporting imagery. Kept subdued so it complements the
   copy rather than competing with it.
   -------------------------------------------------------------------------- */

.nzp-photo {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  border-radius: var(--radius);
  background: var(--color-light-dark);
}

/*
 * Photographs are integrated into the layout rather than dropped in as
 * full-width slabs. Two patterns only:
 *
 *   1. .nzp-photo-split — a photograph sitting beside a block of copy, so
 *      the image reads as part of the section it belongs to.
 *   2. .nzp-hero--photo — a photograph behind the hero under a heavy brand
 *      overlay, so it registers as texture rather than as a picture.
 */

/* Photograph paired with a block of text. */
.nzp-photo-split {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--space-8);
  align-items: center;
}

/* Flip the column order — photo on the left, copy on the right. */
.nzp-photo-split--reverse .nzp-photo-frame { order: -1; }

.nzp-photo-frame {
  aspect-ratio: 4 / 3;
  overflow: hidden;
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow);
}
.nzp-photo-split h2,
.nzp-photo-split h3 { margin-top: 0; }

@media (max-width: 768px) {
  .nzp-photo-split { grid-template-columns: 1fr; gap: var(--space-5); }
  /* On mobile the photo always follows its copy, whichever side it sat on. */
  .nzp-photo-split--reverse .nzp-photo-frame { order: 0; }
  .nzp-photo-frame { aspect-ratio: 16 / 10; }
}

/* Image placeholder wrapper — keeps layout stable while art is pending. */
.nzp-img-placeholder {
  width: 100%;
  aspect-ratio: 16 / 10;
  object-fit: cover;
  background: var(--color-light-dark);
  border-radius: var(--radius);
}

/* Grey box standing in for a partner logo in the carousel. */
.nzp-logo-placeholder {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 180px;
  height: 84px;
  flex: 0 0 180px;
  background: var(--color-bg);
  border: 1px solid var(--color-border);
  border-radius: var(--radius);
  font-size: var(--fs-xs);
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--color-text-muted);
}


/* ==========================================================================
   07. SITE HEADER AND NAVIGATION
   ========================================================================== */

.nzp-header {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  z-index: var(--z-header);
  height: var(--header-h);
  background: var(--color-primary);
  color: var(--color-text-invert);
}

/* Nudge the header down when the WordPress admin bar is present. */
.admin-bar .nzp-header { top: 32px; }

.nzp-header__inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  height: 100%;
  gap: var(--space-5);
  /* Containing block for the centred wordmark on phones. */
  position: relative;
}

.nzp-branding { display: flex; align-items: center; gap: var(--space-3); text-decoration: none; }
.nzp-branding img,
.nzp-branding .custom-logo { height: 40px; width: auto; }
.nzp-branding__name {
  font-size: var(--fs-base);
  font-weight: 600;
  letter-spacing: 0.02em;
  color: var(--color-text-invert);
  white-space: nowrap;
}

/* --- Primary navigation ------------------------------------------------ */
.nzp-nav ul {
  list-style: none;
  display: flex;
  align-items: center;
  gap: var(--space-5);
  margin: 0;
  padding: 0;
}
.nzp-nav li { margin: 0; position: relative; }

.nzp-nav a {
  display: block;
  padding: var(--space-2) 0;
  font-size: var(--fs-sm);
  font-weight: 500;
  color: rgba(255, 255, 255, 0.88);
  text-decoration: none;
  white-space: nowrap;
  transition: color var(--transition);
}
.nzp-nav a:hover,
.nzp-nav .current-menu-item > a,
.nzp-nav .current-menu-ancestor > a,
.nzp-nav .current_page_item > a {
  color: var(--color-secondary);
}

/* --- Dropdown submenus -------------------------------------------------- */
.nzp-nav .sub-menu,
.nzp-nav .children {
  position: absolute;
  top: 100%;
  left: 0;
  z-index: var(--z-dropdown);
  display: block;
  min-width: 220px;
  margin: 0;
  padding: var(--space-2) 0;
  background: var(--color-primary);
  border-top: 2px solid var(--color-secondary);
  box-shadow: var(--shadow-lg);
  opacity: 0;
  visibility: hidden;
  transform: translateY(-6px);
  transition: opacity var(--transition), transform var(--transition), visibility var(--transition);
}
.nzp-nav li:hover > .sub-menu,
.nzp-nav li:focus-within > .sub-menu,
.nzp-nav li.is-open > .sub-menu {
  opacity: 1;
  visibility: visible;
  transform: translateY(0);
}
.nzp-nav .sub-menu li { width: 100%; }
.nzp-nav .sub-menu a { padding: var(--space-2) var(--space-4); font-size: var(--fs-sm); }
.nzp-nav .sub-menu a:hover { background: var(--color-white-20); color: var(--color-secondary); }

/* Caret on items that have a dropdown. */
.nzp-nav .menu-item-has-children > a::after {
  content: '';
  display: inline-block;
  margin-left: var(--space-2);
  border-style: solid;
  border-width: 4px 4px 0 4px;
  border-color: currentColor transparent transparent transparent;
  vertical-align: middle;
}

/* --- Mobile toggle ------------------------------------------------------ */
.nzp-nav-toggle {
  display: none;
  width: 44px;
  height: 44px;
  padding: 0;
  background: transparent;
  border: 0;
  cursor: pointer;
  align-items: center;
  justify-content: center;
}
.nzp-nav-toggle__bars,
.nzp-nav-toggle__bars::before,
.nzp-nav-toggle__bars::after {
  display: block;
  width: 24px;
  height: 2px;
  background: var(--color-text-invert);
  transition: transform var(--transition), opacity var(--transition);
}
.nzp-nav-toggle__bars { position: relative; }
.nzp-nav-toggle__bars::before,
.nzp-nav-toggle__bars::after { content: ''; position: absolute; left: 0; }
.nzp-nav-toggle__bars::before { top: -7px; }
.nzp-nav-toggle__bars::after  { top: 7px; }

.nzp-nav-toggle[aria-expanded="true"] .nzp-nav-toggle__bars { background: transparent; }
.nzp-nav-toggle[aria-expanded="true"] .nzp-nav-toggle__bars::before { transform: translateY(7px) rotate(45deg); }
.nzp-nav-toggle[aria-expanded="true"] .nzp-nav-toggle__bars::after  { transform: translateY(-7px) rotate(-45deg); }


/* ==========================================================================
   08. HERO
   ========================================================================== */

.nzp-hero {
  position: relative;
  background: var(--color-primary);
  color: var(--color-text-invert);
  padding: var(--space-9) 0;
  text-align: center;
  overflow: hidden;
}

/* Subtle radial lift behind the headline. No video. */
.nzp-hero::before {
  content: '';
  position: absolute;
  inset: 0;
  background: radial-gradient(ellipse at 50% 35%, rgba(56, 77, 61, 0.55) 0%, transparent 62%);
  pointer-events: none;
}

/*
 * Hero with a property photograph behind it.
 *
 * The overlay is light enough that the building is clearly visible. Legibility
 * is protected two ways instead of by brute-force darkening:
 *   - a soft radial scrim sits directly behind the text block only, so the
 *     edges of the photograph stay bright;
 *   - the hero text carries a shadow, which holds contrast over the lighter
 *     parts of the image without dimming the photograph further.
 *
 * The photographed building is light-toned, so white text placed straight over
 * it reads as white-on-white. The scrim behind the headline is therefore much
 * stronger than the flat layer: roughly 82% behind the text, easing to 68% at
 * the edges where the building is still clearly readable.
 */
.nzp-hero--photo {
  background-size: cover;
  background-position: center 40%;
  background-repeat: no-repeat;
}
.nzp-hero--photo::before {
  background:
    radial-gradient(ellipse at 50% 40%, rgba(6, 31, 17, 0.52) 0%, rgba(6, 31, 17, 0.16) 72%),
    linear-gradient(rgba(6, 31, 17, 0.62), rgba(6, 31, 17, 0.66));
}

/* Second line of defence: a shadow holds the text against any light patch
   in the photograph without needing to darken the image further. */
.nzp-hero--photo .nzp-hero__inner {
  text-shadow: 0 2px 20px rgba(6, 31, 17, 0.95), 0 1px 4px rgba(6, 31, 17, 0.8);
}
.nzp-hero--photo .nzp-hero__text { color: rgba(255, 255, 255, 0.96); }

.nzp-hero__inner { position: relative; max-width: 860px; margin: 0 auto; }
.nzp-hero h1 {
  color: var(--color-text-invert);
  font-size: clamp(2.25rem, 5vw, 3.5rem);
  margin-bottom: var(--space-5);
}
.nzp-hero__text {
  font-size: var(--fs-md);
  line-height: 1.75;
  color: rgba(255, 255, 255, 0.82);
  margin-bottom: var(--space-6);
}


/* ==========================================================================
   09. KPI CARDS
   ========================================================================== */

.nzp-kpi-grid {
  display: grid;
  grid-template-columns: repeat(5, 1fr);
  gap: var(--space-4);
}

.nzp-kpi {
  background: var(--color-bg);
  border-top: 3px solid var(--color-secondary);
  border-radius: 0 0 var(--radius) var(--radius);
  padding: var(--space-6) var(--space-4);
  text-align: center;
  box-shadow: var(--shadow-sm);
  transition: transform var(--transition), box-shadow var(--transition);
}
.nzp-kpi:hover { transform: translateY(-3px); box-shadow: var(--shadow); }

.nzp-kpi__value {
  display: block;
  font-family: var(--font-display);
  font-size: clamp(1.75rem, 3vw, 2.5rem);
  font-weight: 400;
  line-height: 1.1;
  color: var(--color-primary);
  margin-bottom: var(--space-3);
  word-break: break-word;
}
/* Muted treatment when the figure is still pending. */
.nzp-kpi__value.nzp-tbd { color: var(--color-text-muted); font-family: var(--font-sans); font-size: var(--fs-xl); }

.nzp-kpi__label {
  display: block;
  font-size: var(--fs-xs);
  font-weight: 600;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--color-text-muted);
  line-height: 1.4;
}


/* ==========================================================================
   10. CONTENT CARDS AND FEATURE BLOCKS
   ========================================================================== */

.nzp-card {
  background: var(--color-bg);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-lg);
  padding: var(--space-6);
  height: 100%;
  transition: transform var(--transition), box-shadow var(--transition), border-color var(--transition);
}
.nzp-card:hover {
  transform: translateY(-3px);
  box-shadow: var(--shadow);
  border-color: var(--color-secondary);
}
.nzp-card h3 { margin-bottom: var(--space-3); }
.nzp-card p  { color: var(--color-text-muted); margin-bottom: 0; }

/* Numbered badge used on the asset-management cards. */
.nzp-card__badge {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 44px;
  height: 44px;
  margin-bottom: var(--space-4);
  border-radius: 50%;
  background: var(--color-secondary-20);
  color: var(--color-primary);
  font-weight: 700;
  font-size: var(--fs-md);
}

/* Simple bullet list with sand markers.
   Colour is inherited so list copy always matches the surrounding text. */
.nzp-list { list-style: none; padding: 0; margin: var(--space-4) 0 0; }
.nzp-list li {
  position: relative;
  padding-left: var(--space-5);
  margin-bottom: var(--space-3);
  color: inherit;
}
.nzp-list li::before {
  content: '';
  position: absolute;
  left: 0;
  top: 0.65em;
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--color-secondary);
}

/* Post card, reused on the homepage news grid and the blog index. */
.nzp-post-card {
  display: flex;
  flex-direction: column;
  background: var(--color-bg);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-lg);
  overflow: hidden;
  height: 100%;
  transition: transform var(--transition), box-shadow var(--transition);
}
.nzp-post-card:hover { transform: translateY(-3px); box-shadow: var(--shadow); }
.nzp-post-card__media { display: block; aspect-ratio: 16 / 10; overflow: hidden; background: var(--color-light-dark); }
.nzp-post-card__media img {
  width: 100%; height: 100%; object-fit: cover;
  transition: transform 400ms ease;
}
.nzp-post-card:hover .nzp-post-card__media img { transform: scale(1.04); }
.nzp-post-card__body { display: flex; flex-direction: column; flex: 1; padding: var(--space-5); }
.nzp-post-card__date {
  font-size: var(--fs-xs);
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--color-secondary);
  margin-bottom: var(--space-2);
}
.nzp-post-card__title { font-size: var(--fs-lg); margin-bottom: var(--space-3); }
.nzp-post-card__title a { text-decoration: none; color: inherit; }
.nzp-post-card__title a:hover { color: var(--color-primary-90); }
.nzp-post-card__excerpt { flex: 1; color: var(--color-text-muted); font-size: var(--fs-sm); margin-bottom: var(--space-4); }

/* Empty-state panel when a query returns nothing. */
.nzp-empty {
  padding: var(--space-8) var(--space-6);
  text-align: center;
  background: var(--color-bg-alt);
  border-radius: var(--radius-lg);
  color: var(--color-text-muted);
}


/* ==========================================================================
   11. MAPS
   ========================================================================== */

.nzp-map { width: 100%; max-width: 720px; margin: 0 auto; }
/*
 * Clipped to the viewBox. With overflow visible, every country outside the
 * cropped window still painted - spilling the landmass across the full width
 * of the section, behind the heading, and leaving stray strokes elsewhere on
 * the page where a coastline happened to pass.
 */
.nzp-map svg { width: 100%; height: auto; overflow: hidden; }

/* Both maps are drawn on portrait viewBoxes, so they are capped narrower
   than the default container to stop them dominating their section. */
.nzp-map--office  { max-width: 720px; }
.nzp-map--germany { max-width: 400px; }
/* The Overview map is the page's centrepiece, so it runs larger there. */
.nzp-grid .nzp-map--germany { max-width: 560px; }

/* Country fills: flat, low contrast, so the office pins carry the emphasis. */
.nzp-map--office .nzp-map__landmass path {
  fill: rgba(255, 255, 255, 0.14);
  stroke: rgba(255, 255, 255, 0.34);
  stroke-width: 1.2;
  stroke-linejoin: round;
}

/* --- Office map (Europe, 4 pins) --------------------------------------- */
.nzp-map__landmass { fill: var(--color-primary-90); stroke: var(--color-white-20); stroke-width: 0.5; }

.nzp-pin { cursor: pointer; }
.nzp-pin__dot {
  fill: var(--color-secondary);
  transition: r 200ms ease, fill 200ms ease;
}
.nzp-pin__pulse {
  fill: var(--color-secondary);
  opacity: 0.35;
  transform-box: fill-box;
  transform-origin: center;
  animation: nzp-pulse 2.4s cubic-bezier(0.455, 0.03, 0.515, 0.955) infinite;
}
/* text-anchor is deliberately NOT set here — it is supplied per pin as an
   attribute so labels can sit left or right of their dot. A CSS declaration
   would override that attribute and stack the labels on top of each other. */
.nzp-pin__label {
  font-family: var(--font-sans);
  font-size: 14px;
  font-weight: 600;
  fill: var(--color-text-invert);
  pointer-events: none;
  paint-order: stroke;
  stroke: rgba(6, 31, 17, 0.65);
  stroke-width: 3px;
  transition: fill 200ms ease;
}
.nzp-pin:hover .nzp-pin__dot,
.nzp-pin.is-active /* --- Office markers ------------------------------------------------------ */
.nzp-pin { cursor: pointer; }
.nzp-pin__shadow { fill: rgba(0, 0, 0, 0.45); }
.nzp-pin__body { transition: transform 200ms cubic-bezier(0.34, 1.4, 0.64, 1); }
.nzp-pin__teardrop {
  fill: var(--color-secondary);
  stroke: #FFFFFF;
  stroke-width: 1.8;
  stroke-linejoin: round;
  transition: fill 180ms ease;
}
.nzp-pin__eye { fill: var(--color-primary); transition: fill 180ms ease; }

/* Grows from the tip, so the marker keeps pointing at the same spot. */
.nzp-pin:hover .nzp-pin__body,
.nzp-pin.is-active .nzp-pin__body { transform: scale(1.28); }
.nzp-pin:hover .nzp-pin__teardrop,
.nzp-pin.is-active .nzp-pin__teardrop { fill: #D93025; }
.nzp-pin:hover .nzp-pin__eye,
.nzp-pin.is-active .nzp-pin__eye { fill: #FFFFFF; }
.nzp-pin:hover .nzp-pin__label,
.nzp-pin.is-active .nzp-pin__label { fill: var(--color-secondary); }

@keyframes nzp-pulse {
  0%, 100% { transform: scale(0.8); opacity: 0.35; }
  50%      { transform: scale(1.6); opacity: 0; }
}

/* Office list beneath the map. */
.nzp-office-list {
  display: grid;
  /* One column per office, however many there are, so adding Hamburg does not
     drop a lone item onto a second row. */
  grid-auto-flow: column;
  grid-auto-columns: minmax(0, 1fr);
  gap: var(--space-4);
  margin-top: var(--space-7);
  list-style: none;
  padding: 0;
}
.nzp-office-list li {
  margin: 0;
  padding: var(--space-3) var(--space-2);
  text-align: center;
  background: var(--color-white-20);
  border-radius: var(--radius);
  font-weight: 600;
  font-size: var(--fs-sm);
  letter-spacing: 0.04em;
  color: var(--color-text-invert);
  transition: background var(--transition);
}
.nzp-office-list li.is-active { background: var(--color-secondary); color: var(--color-primary); }

/* --- Germany region map ------------------------------------------------- */
.nzp-region { transition: opacity var(--transition); cursor: pointer; }
.nzp-region:hover { opacity: 0.82; }
.nzp-region__shape { stroke: var(--color-bg); stroke-width: 1.5; }
.nzp-region__label {
  font-family: var(--font-sans);
  font-size: 13px;
  font-weight: 700;
  fill: #FFFFFF;
  text-anchor: middle;
  pointer-events: none;
}

.nzp-legend { list-style: none; padding: 0; margin: var(--space-6) 0 0; }
.nzp-legend li {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  padding: var(--space-3) 0;
  border-bottom: 1px solid var(--color-border);
  margin: 0;
}
.nzp-legend li:last-child { border-bottom: 0; }
.nzp-legend__swatch { width: 16px; height: 16px; border-radius: 3px; flex: 0 0 16px; }
.nzp-legend__name  { flex: 1; font-weight: 500; }
.nzp-legend__value { font-weight: 700; font-variant-numeric: tabular-nums; color: var(--color-primary); }


/* ==========================================================================
   12. TIMELINE (TRACK RECORD)
   --------------------------------------------------------------------------
   Horizontal on desktop, vertical on mobile.
   ========================================================================== */

.nzp-timeline { position: relative; }

.nzp-timeline__track {
  display: grid;
  grid-auto-flow: column;
  grid-auto-columns: 1fr;
  gap: var(--space-4);
  position: relative;
  padding-top: var(--space-7);
}
/* The connecting rail. */
.nzp-timeline__track::before {
  content: '';
  position: absolute;
  top: 14px;
  left: 6%;
  right: 6%;
  height: 2px;
  background: var(--color-secondary-20);
}

.nzp-timeline__step { position: relative; text-align: center; padding: 0 var(--space-2); }
.nzp-timeline__step::before {
  content: '';
  position: absolute;
  top: -50px;
  left: 50%;
  transform: translateX(-50%);
  width: 14px;
  height: 14px;
  border-radius: 50%;
  background: var(--color-bg);
  border: 3px solid var(--color-secondary);
}
.nzp-timeline__step--current::before { background: var(--color-secondary); }

.nzp-timeline__year {
  display: block;
  font-family: var(--font-display);
  font-size: var(--fs-xl);
  color: var(--color-primary);
  margin-bottom: var(--space-2);
}
.nzp-timeline__added {
  display: block;
  font-size: var(--fs-sm);
  color: var(--color-text-muted);
  margin-bottom: var(--space-2);
}
.nzp-timeline__total {
  display: inline-block;
  padding: var(--space-1) var(--space-3);
  font-size: var(--fs-sm);
  font-weight: 700;
  color: var(--color-primary);
  background: var(--color-secondary-20);
  border-radius: 999px;
}


/* ==========================================================================
   13. SDG CARDS (ESG FRAMEWORK)
   ========================================================================== */

.nzp-sdg {
  display: flex;
  flex-direction: column;
  border-radius: var(--radius-lg);
  overflow: hidden;
  box-shadow: var(--shadow-sm);
  height: 100%;
  transition: transform var(--transition), box-shadow var(--transition);
}
.nzp-sdg:hover { transform: translateY(-3px); box-shadow: var(--shadow); }

/* Colour band uses the official UN SDG colour, set inline per card. */
.nzp-sdg__band {
  padding: var(--space-5);
  color: #FFFFFF;
  display: flex;
  align-items: baseline;
  gap: var(--space-3);
}
.nzp-sdg__number { font-size: var(--fs-2xl); font-weight: 700; line-height: 1; }
.nzp-sdg__name   { font-size: var(--fs-md); font-weight: 600; line-height: 1.25; }
.nzp-sdg__body   { flex: 1; padding: var(--space-5); background: var(--color-bg); }
.nzp-sdg__body p { color: var(--color-text-muted); font-size: var(--fs-sm); margin: 0; }


/* ==========================================================================
   14. MANAGE TO GREEN
   ========================================================================== */

/*
 * Both step columns must start at the same vertical position regardless of
 * how many lines each item wraps to. `align-items: center` previously made
 * the shorter column float down against the taller one; `start` pins every
 * column to the top of the row.
 */
.nzp-phases {
  display: grid;
  grid-template-columns: 1fr minmax(280px, 1.15fr) 1fr;
  gap: var(--space-6);
  align-items: start;
}

/* Fixed heading height keeps the first step of each column on the same line. */
.nzp-phase-col h3 {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  min-height: 44px;
  margin-bottom: var(--space-5);
}
.nzp-phase-col--right { text-align: right; }
.nzp-phase-col--right h3 { justify-content: flex-end; }
.nzp-phase-col--right .nzp-phase-step { flex-direction: row-reverse; text-align: right; }

.nzp-phase-badge {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 32px;
  height: 32px;
  border-radius: 50%;
  font-size: var(--fs-sm);
  font-weight: 700;
  flex: 0 0 32px;
}
.nzp-phase-badge--1 { background: var(--color-light-dark); color: var(--color-text-muted); }
.nzp-phase-badge--2 { background: var(--color-secondary); color: var(--color-primary); }

.nzp-phase-step {
  display: flex;
  align-items: flex-start;
  gap: var(--space-3);
  margin-bottom: var(--space-4);
}
.nzp-phase-step__marker {
  flex: 0 0 10px;
  width: 10px;
  height: 10px;
  margin-top: 0.55em;
  border-radius: 50%;
}
.nzp-phase-step--muted .nzp-phase-step__marker { background: var(--color-text-muted); opacity: 0.5; }
.nzp-phase-step--active .nzp-phase-step__marker { background: var(--color-green-light); }

/* "Phase one" / "Phase two" picked out where they open a paragraph. */
.nzp-phase-word { color: var(--color-green-accent); font-weight: 700; }

/* Phase 2: each marker carries the colour of its element on the building. */
.nzp-phase-step--heatpump .nzp-phase-step__marker { background: var(--color-heatpump); }
.nzp-phase-step--pv       .nzp-phase-step__marker { background: var(--color-pv); }
.nzp-phase-step--control     .nzp-phase-step__marker { background: var(--color-control); }
.nzp-phase-step--envelope .nzp-phase-step__marker { background: var(--color-envelope); }

/* Slightly larger markers on the coded steps so the colour reads clearly. */
.nzp-phase-step--heatpump .nzp-phase-step__marker,
.nzp-phase-step--pv       .nzp-phase-step__marker,
.nzp-phase-step--control     .nzp-phase-step__marker,
.nzp-phase-step--envelope .nzp-phase-step__marker {
  flex-basis: 12px;
  width: 12px;
  height: 12px;
}

.nzp-phase-step__title { display: block; font-weight: 600; margin-bottom: 2px; }
.nzp-phase-step__text  { display: block; font-size: var(--fs-sm); color: var(--color-text-muted); }

/* The single building rendered across both phases. */
.nzp-house { width: 100%; max-width: 420px; margin: 0 auto; }
.nzp-house svg { width: 100%; height: auto; }
.nzp-house__divider { stroke: var(--color-secondary); stroke-width: 2; stroke-dasharray: 6 5; }
.nzp-house__phase-label {
  font-family: var(--font-sans);
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  text-anchor: middle;
}

/* --- Partner carousel --------------------------------------------------- */
.nzp-carousel {
  position: relative;
  overflow: hidden;
  padding: var(--space-5) 0;
  /* Fade the strip out at both edges. */
  -webkit-mask-image: linear-gradient(to right, transparent, #000 8%, #000 92%, transparent);
          mask-image: linear-gradient(to right, transparent, #000 8%, #000 92%, transparent);
}
.nzp-carousel__track {
  display: flex;
  align-items: center;
  gap: var(--space-5);
  width: max-content;
  animation: nzp-scroll 40s linear infinite;
}
.nzp-carousel:hover .nzp-carousel__track { animation-play-state: paused; }

@keyframes nzp-scroll {
  from { transform: translateX(0); }
  /* The track holds two identical halves, so -50% is a seamless loop. */
  to   { transform: translateX(-50%); }
}

.nzp-carousel__category {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-3);
}
.nzp-carousel__category-name {
  font-size: var(--fs-xs);
  font-weight: 700;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--color-secondary);
}

.nzp-doc-list { list-style: none; padding: 0; margin: 0; }
.nzp-doc-list li {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-4);
  padding: var(--space-4);
  margin-bottom: var(--space-3);
  background: var(--color-bg);
  border: 1px solid var(--color-border);
  border-radius: var(--radius);
}


/* ==========================================================================
   16. PRESS CARDS
   ========================================================================== */

.nzp-press-card {
  display: flex;
  flex-direction: column;
  height: 100%;
  padding: var(--space-6);
  background: var(--color-bg);
  border: 1px solid var(--color-border);
  border-left: 3px solid var(--color-secondary);
  border-radius: 0 var(--radius-lg) var(--radius-lg) 0;
  transition: transform var(--transition), box-shadow var(--transition);
}
.nzp-press-card:hover { transform: translateY(-3px); box-shadow: var(--shadow); }

.nzp-press-card__meta {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-2);
  margin-bottom: var(--space-3);
  font-size: var(--fs-xs);
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--color-text-muted);
}
.nzp-press-card__source { color: var(--color-pv); font-weight: 700; }
.nzp-press-card .nzp-link-arrow { color: var(--color-gold-dark); }
.nzp-press-card .nzp-link-arrow:hover { color: var(--color-secondary); }
.nzp-press-card__sep { opacity: 0.5; }
.nzp-press-card__title {
  font-size: var(--fs-md);
  font-family: var(--font-sans);
  font-weight: 600;
  line-height: 1.4;
  flex: 1;
  margin-bottom: var(--space-5);
}


/* ==========================================================================
   17. CONTACT
   ========================================================================== */

/* The contact page carries the form only — address, email and phone appear
   in the footer on every page, so repeating them here was redundant. */
.nzp-contact-grid {
  display: block;
  width: 100%;
  max-width: none;
  margin: 0;
}

.nzp-contact-details { list-style: none; padding: 0; margin: 0; }
.nzp-contact-details li { margin-bottom: var(--space-5); }
.nzp-contact-details dt,
.nzp-contact-details__label {
  display: block;
  font-size: var(--fs-xs);
  font-weight: 700;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--color-secondary);
  margin-bottom: var(--space-1);
}
.nzp-contact-details a { text-decoration: none; font-weight: 500; }
.nzp-contact-details a:hover { text-decoration: underline; }

/* --- Form controls (also styles Contact Form 7 output) ------------------ */
input[type="text"],
input[type="email"],
input[type="url"],
input[type="tel"],
input[type="password"],
input[type="search"],
textarea,
select {
  width: 100%;
  padding: var(--space-3);
  font-family: var(--font-sans);
  font-size: var(--fs-base);
  color: var(--color-text);
  background: var(--color-bg);
  border: 1px solid var(--color-border);
  border-radius: var(--radius);
  transition: border-color var(--transition), box-shadow var(--transition);
}
input:focus,
textarea:focus,
select:focus {
  outline: none;
  border-color: var(--color-secondary);
  box-shadow: 0 0 0 3px var(--color-secondary-20);
}
/*
 * Message fields get real room to type in. Contact Form 7 emits a plain
 * <textarea> whose rows attribute is often left at the default, so the
 * min-height here is what actually determines the visible size. It applies
 * to both the CF7 form and the theme's own fallback form.
 */
textarea,
.wpcf7 textarea,
.wpcf7-textarea {
  min-height: 220px;
  line-height: 1.6;
  resize: vertical;
}

.nzp-form-field { margin-bottom: var(--space-4); }
.nzp-form-field label {
  display: block;
  font-size: var(--fs-sm);
  font-weight: 600;
  margin-bottom: var(--space-2);
}
.nzp-form-field .required { color: #B3462F; }

input[type="submit"],
button[type="submit"],
.wpcf7 input[type="submit"] {
  display: inline-block;
  padding: var(--space-3) var(--space-6);
  font-family: var(--font-sans);
  font-size: var(--fs-base);
  font-weight: 600;
  color: var(--color-text-invert);
  background: var(--color-primary);
  border: 0;
  border-radius: var(--radius);
  cursor: pointer;
  transition: background var(--transition);
}
input[type="submit"]:hover,
button[type="submit"]:hover,
.wpcf7 input[type="submit"]:hover { background: var(--color-primary-90); }

/* Contact Form 7 response messages. */
.wpcf7 form .wpcf7-response-output {
  margin: var(--space-4) 0 0;
  padding: var(--space-3) var(--space-4);
  border-width: 1px;
  border-radius: var(--radius);
  font-size: var(--fs-sm);
}
.wpcf7-not-valid-tip { color: #B3462F; font-size: var(--fs-sm); margin-top: var(--space-1); }


/* ==========================================================================
   18. BLOG
   ========================================================================== */

.nzp-post-meta {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-3);
  margin-bottom: var(--space-5);
  font-size: var(--fs-sm);
  color: var(--color-text-muted);
}
.nzp-post-meta__sep { opacity: 0.5; }

.nzp-entry-content { font-size: var(--fs-md); line-height: 1.8; }
.nzp-entry-content > * + * { margin-top: var(--space-5); }
.nzp-entry-content h2 { margin-top: var(--space-7); }
.nzp-entry-content h3 { margin-top: var(--space-6); }
.nzp-entry-content img { border-radius: var(--radius); }

.nzp-featured-image { margin-bottom: var(--space-6); }
.nzp-featured-image img { width: 100%; border-radius: var(--radius-lg); }

.nzp-tags { display: flex; flex-wrap: wrap; gap: var(--space-2); margin-top: var(--space-6); }
.nzp-tags a {
  display: inline-block;
  padding: var(--space-1) var(--space-3);
  font-size: var(--fs-xs);
  font-weight: 600;
  color: var(--color-primary);
  background: var(--color-secondary-20);
  border-radius: 999px;
  text-decoration: none;
}
.nzp-tags a:hover { background: var(--color-secondary); }

/* Previous / next post navigation. */
.nzp-post-nav {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--space-4);
  margin-top: var(--space-8);
  padding-top: var(--space-6);
  border-top: 1px solid var(--color-border);
}
.nzp-post-nav a {
  display: block;
  padding: var(--space-4);
  border: 1px solid var(--color-border);
  border-radius: var(--radius);
  text-decoration: none;
  transition: border-color var(--transition);
}
.nzp-post-nav a:hover { border-color: var(--color-secondary); }
.nzp-post-nav__label {
  display: block;
  font-size: var(--fs-xs);
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--color-secondary);
  margin-bottom: var(--space-1);
}
.nzp-post-nav__next { text-align: right; }

/* Pagination. */
.nzp-pagination { margin-top: var(--space-8); }
.nzp-pagination .nav-links { display: flex; flex-wrap: wrap; justify-content: center; gap: var(--space-2); }
.nzp-pagination .page-numbers {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 42px;
  height: 42px;
  padding: 0 var(--space-3);
  border: 1px solid var(--color-border);
  border-radius: var(--radius);
  text-decoration: none;
  font-weight: 600;
  font-size: var(--fs-sm);
  transition: background var(--transition), border-color var(--transition), color var(--transition);
}
.nzp-pagination .page-numbers:hover { border-color: var(--color-secondary); }
.nzp-pagination .page-numbers.current {
  background: var(--color-primary);
  border-color: var(--color-primary);
  color: var(--color-text-invert);
}

/* Comments. */
.nzp-comments { margin-top: var(--space-8); padding-top: var(--space-6); border-top: 1px solid var(--color-border); }
.nzp-comments .comment-list { list-style: none; padding: 0; }
.nzp-comments .comment-list li { margin-bottom: var(--space-5); }
.nzp-comments .comment-body {
  padding: var(--space-5);
  background: var(--color-bg-alt);
  border-radius: var(--radius);
}
.nzp-comments .comment-author { font-weight: 600; }
.nzp-comments .comment-metadata { font-size: var(--fs-xs); color: var(--color-text-muted); margin-bottom: var(--space-3); }

/* Sidebar. */
.nzp-blog-layout { display: grid; grid-template-columns: 1fr 300px; gap: var(--space-8); align-items: start; }
.nzp-sidebar .widget {
  padding: var(--space-5);
  margin-bottom: var(--space-5);
  background: var(--color-bg-alt);
  border-radius: var(--radius-lg);
}
.nzp-sidebar .widget-title { font-size: var(--fs-md); font-family: var(--font-sans); margin-bottom: var(--space-4); }
.nzp-sidebar ul { list-style: none; padding: 0; margin: 0; }
.nzp-sidebar li { margin-bottom: var(--space-2); }


/* ==========================================================================
   19. 404
   ========================================================================== */

.nzp-404 { text-align: center; padding: var(--space-9) 0; }
.nzp-404__code {
  font-family: var(--font-display);
  font-size: clamp(5rem, 16vw, 10rem);
  line-height: 1;
  color: var(--color-secondary);
  margin-bottom: var(--space-4);
}


/* ==========================================================================
   20. SITE FOOTER
   ========================================================================== */

.nzp-footer { background: var(--color-primary); color: rgba(255, 255, 255, 0.78); }

/* Two columns: company details, then navigation (Imprint included). */
.nzp-footer__main {
  display: grid;
  grid-template-columns: 1.6fr 1fr;
  gap: var(--space-7);
  padding: var(--space-8) 0;
}
.nzp-footer h2,
.nzp-footer h3 { color: var(--color-text-invert); }
.nzp-footer h3 {
  font-family: var(--font-sans);
  font-size: var(--fs-sm);
  font-weight: 700;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  margin-bottom: var(--space-4);
}
.nzp-footer a { color: var(--color-secondary); text-decoration: none; }
.nzp-footer a:hover { color: var(--color-text-invert); }

.nzp-footer__menu { list-style: none; padding: 0; margin: 0; }
.nzp-footer__menu li { margin-bottom: var(--space-2); }

/* Social icons. Colour comes from a single token, so the old mismatch
   between the icon fill (#CEA690) and the brand sand (#DBAE95) cannot recur. */
.nzp-social { display: flex; gap: var(--space-2); margin-top: var(--space-4); }
.nzp-social a {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 38px;
  height: 38px;
  border-radius: 50%;
  color: var(--color-secondary);
  transition: background var(--transition), color var(--transition);
}
.nzp-social a:hover { background: var(--color-white-20); color: var(--color-text-invert); }
.nzp-social svg { width: 20px; height: 20px; fill: currentColor; }

.nzp-footer__bottom {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
  padding: var(--space-4) 0;
  border-top: 1px solid var(--color-white-20);
  font-size: var(--fs-sm);
}
/*
 * Impressum and Datenschutz sit at the opposite end of the copyright row.
 * They are the only links in a row that is otherwise plain small print, so
 * they take an underline on hover to read as links, and never wrap mid-word.
 */
.nzp-footer__legal a { white-space: nowrap; }
.nzp-footer__legal a:hover { text-decoration: underline; }

.nzp-footer__widgets { padding-top: var(--space-6); }


/* ==========================================================================
   21. ACCESSIBILITY HELPERS
   ========================================================================== */

.screen-reader-text {
  position: absolute !important;
  width: 1px; height: 1px;
  padding: 0; margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}
.screen-reader-text:focus {
  position: fixed !important;
  top: var(--space-3); left: var(--space-3);
  z-index: 100000;
  width: auto; height: auto;
  padding: var(--space-3) var(--space-5);
  clip: auto;
  background: var(--color-bg);
  color: var(--color-primary);
  border-radius: var(--radius);
  box-shadow: var(--shadow-lg);
  font-weight: 600;
}

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

/* Honour the OS "reduce motion" setting. */
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *,
  *::before,
  *::after {
    animation-duration: 0.001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.001ms !important;
  }
  .nzp-carousel__track { animation: none; }
}


/* ==========================================================================
   22. RESPONSIVE (<= 768px)
   ========================================================================== */

@media (max-width: 768px) {

  :root { --header-h: var(--header-h-mob); }

  .admin-bar .nzp-header { top: 46px; }

  /* --- Navigation collapses to a slide-down panel --- */
  .nzp-nav-toggle { display: flex; }

  .nzp-nav {
    position: fixed;
    top: var(--header-h-mob);
    left: 0;
    right: 0;
    max-height: calc(100vh - var(--header-h-mob));
    overflow-y: auto;
    background: var(--color-primary);
    border-top: 1px solid var(--color-white-20);
    transform: translateY(-8px);
    opacity: 0;
    visibility: hidden;
    transition: opacity var(--transition), transform var(--transition), visibility var(--transition);
  }
  .admin-bar .nzp-nav { top: calc(var(--header-h-mob) + 46px); }

  .nzp-nav.is-open { opacity: 1; visibility: visible; transform: translateY(0); }

  .nzp-nav ul { flex-direction: column; align-items: stretch; gap: 0; }
  .nzp-nav > ul > li { border-bottom: 1px solid var(--color-white-20); }
  .nzp-nav a { padding: var(--space-4); font-size: var(--fs-base); }

  /*
   * Submenus stay collapsed until their parent is tapped.
   *
   * display:none, NOT visibility - and that distinction was a real bug, not
   * a preference. visibility is inherited but a descendant may re-declare
   * visibility:visible and escape a hidden ancestor, which is what the old
   * rule did. So while the panel was shut (visibility:hidden, opacity:0)
   * every submenu link stayed laid out and hit-testable across the top of
   * the page: invisible at opacity 0, but still the thing your finger hit.
   * Tapping a form field or anything else in the upper half of a page
   * navigated to Overview, Track Record and so on instead. display:none
   * removes the box entirely and cannot be escaped that way.
   */
  .nzp-nav .sub-menu {
    position: static;
    display: none;
    opacity: 1;
    transform: none;
    box-shadow: none;
    border-top: 0;
    padding: 0 0 var(--space-2);
    background: rgba(0, 0, 0, 0.18);
    min-width: 0;
  }
  .nzp-nav .menu-item-has-children.is-open > .sub-menu { display: block; }

  .nzp-nav .sub-menu a { padding-left: var(--space-6); }
  .nzp-nav .menu-item-has-children > a::after {
    float: right;
    margin-top: 0.6em;
    transition: transform var(--transition);
  }
  .nzp-nav .menu-item-has-children.is-open > a::after { transform: rotate(180deg); }

  /* --- Layout stacking --- */
  .nzp-grid--2,
  .nzp-grid--3,
  .nzp-grid--4 { grid-template-columns: 1fr; }

  .nzp-kpi-grid { grid-template-columns: repeat(2, 1fr); }
  .nzp-kpi-grid > :last-child:nth-child(odd) { grid-column: 1 / -1; }

  .nzp-office-list { grid-auto-flow: row; grid-template-columns: repeat(2, 1fr); }

  .nzp-contact-grid,
  .nzp-blog-layout { grid-template-columns: 1fr; }

  .nzp-section { padding-top: var(--space-7); padding-bottom: var(--space-7); }
  .nzp-hero { padding: var(--space-8) 0; }

  /* --- Timeline flips to vertical --- */
  .nzp-timeline__track {
    grid-auto-flow: row;
    grid-auto-columns: auto;
    gap: var(--space-6);
    padding-top: 0;
    padding-left: var(--space-6);
  }
  .nzp-timeline__track::before {
    top: 8px;
    bottom: 8px;
    left: 6px;
    right: auto;
    width: 2px;
    height: auto;
  }
  .nzp-timeline__step { text-align: left; padding: 0; }
  .nzp-timeline__step::before { top: 6px; left: -26px; transform: none; }

  /* --- Manage-to-Green stacks: Phase 1, illustration, Phase 2 --- */
  .nzp-phases { grid-template-columns: 1fr; }
  .nzp-phase-col--right { text-align: left; }
  .nzp-phase-col--right h3 { justify-content: flex-start; }
  .nzp-phase-col--right .nzp-phase-step { flex-direction: row; text-align: left; }
  .nzp-house { order: -1; }

  .nzp-post-nav { grid-template-columns: 1fr; }
  .nzp-post-nav__next { text-align: left; }

  .nzp-footer__main { grid-template-columns: 1fr; gap: var(--space-6); }
  .nzp-footer__bottom { flex-direction: column; align-items: flex-start; }

}

@media (max-width: 480px) {
  .nzp-office-list { grid-auto-flow: row; grid-template-columns: 1fr; }

  /*
   * The wordmark used to be hidden here, which left the phone header as a
   * leaf on one side, a burger on the other and a wide empty gap between.
   * It is centred in the bar instead: the mark stays left, the burger stays
   * right, and the name sits between them.
   */
  .nzp-branding__name {
    display: block;
    position: absolute;
    left: 50%;
    transform: translateX(-50%);
    white-space: nowrap;
    font-size: 1rem;
    /*
     * It is inside the branding anchor, so it should take you home like the
     * mark does. It was made inert to keep it off the burger; capping its
     * width does that without costing the tap.
     */
    pointer-events: auto;
    max-width: calc(100% - 140px);
    overflow: hidden;
    text-overflow: ellipsis;
  }
}


/* ==========================================================================
   24. VIDEO HEADERS AND HERO VIDEO
   ========================================================================== */

/* --- Homepage hero video ------------------------------------------------ */
.nzp-hero-video {
  position: relative;
  width: 100%;
  /* No longer a heading band, so it carries a proper hero height. */
  height: 74vh;
  min-height: 560px;
  max-height: 880px;
  overflow: hidden;
  background: var(--color-primary);
}
.nzp-hero-video video {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}
/* Slight brand tint so the video sits in the palette. */
.nzp-hero-video::after {
  content: '';
  position: absolute;
  inset: 0;
  background: linear-gradient(rgba(6, 31, 17, 0.18), rgba(6, 31, 17, 0.32));
  pointer-events: none;
}

/* The copy that used to sit inside the hero now forms its own section. */
.nzp-hero-copy {
  position: relative;
  background: var(--color-primary);
  background-size: cover;
  background-position: center;
  color: var(--color-text-invert);
  padding: var(--space-9) 0;
  text-align: center;
  overflow: hidden;
}
/*
 * Brand-green wash over the photograph. Weighted slightly heavier at the
 * bottom, where the body copy sits: enough to hold white text against a
 * bright daylight aerial without burying the building underneath it.
 */
.nzp-hero-copy::before {
  content: '';
  position: absolute;
  inset: 0;
  background: linear-gradient(rgba(6, 31, 17, 0.60), rgba(6, 31, 17, 0.76));
  pointer-events: none;
}
.nzp-hero-copy > .nzp-container { position: relative; z-index: 1; }

/*
 * White, heavy and tightly tracked. The sand tone was a light peach that went
 * muddy over photography and read as decorative rather than institutional;
 * sand is now reserved for rules, eyebrows and links. The outline stroke is
 * gone too, since at display sizes it reads as an outline effect rather than
 * as typography.
 */
.nzp-hero-copy h1 {
  color: #FFFFFF;
  font-weight: 700;
  letter-spacing: -0.02em;
  text-shadow:
    0 1px 2px rgba(6, 31, 17, 0.95),
    0 4px 16px rgba(6, 31, 17, 0.75),
    0 12px 44px rgba(6, 31, 17, 0.55);
}
.nzp-hero-copy h1 {
  font-size: clamp(2.1rem, 4.6vw, 3.4rem);
  margin-bottom: var(--space-5);
}
.nzp-hero-copy__text {
  max-width: 860px;
  margin: 0 auto var(--space-5);
  font-size: var(--fs-md);
  line-height: 1.75;
  color: rgba(255, 255, 255, 0.86);
}

/* --- Page header with a looping background video ------------------------ */
.nzp-page-header--video {
  position: relative;
  height: 300px;
  padding: 0;
  overflow: hidden;
  display: flex;
  align-items: center;
}
.nzp-page-header__video {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  z-index: 0;
}
.nzp-page-header__overlay {
  position: relative;
  z-index: 1;
  width: 100%;
  background: rgba(0, 0, 0, 0.4);
  padding: var(--space-6) 0;
}
.nzp-page-header__subtitle {
  margin: 0;
  text-align: center;
  color: #FFFFFF;
  font-size: var(--fs-lg);
  font-weight: 500;
  line-height: 1.5;
  text-shadow: 0 2px 12px rgba(0, 0, 0, 0.6);
}

/* --- Contact header: envelope icon + wordmark --------------------------- */
.nzp-page-header--contact { padding: var(--space-7) 0; }
.nzp-page-header__mark {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-3);
  margin-top: var(--space-3);
}
.nzp-page-header__mark img { height: 36px; width: auto; }
.nzp-envelope {
  width: 56px;
  height: 56px;
  margin: 0 auto;
  display: block;
  stroke: var(--color-secondary);
  fill: none;
  stroke-width: 1.6;
}


/* ==========================================================================
   25. ANIMATED HEADER LOGO
   ========================================================================== */

.nzp-logo-animation {
  height: 50px;
  width: 50px;
  object-fit: contain;
  display: block;
  flex: 0 0 auto;
  background: transparent;
  /*
   * The animation is a white mark on solid black; H.264 carries no alpha, so
   * `background: transparent` above does nothing and the mark sat in a black
   * square on the dark green bar. Screen blending drops the black to the
   * backdrop and leaves the white mark, which is what transparency would have
   * given us if the format supported it.
   */
  mix-blend-mode: screen;
}

/* Small outlined CTA living in the header rather than the hero. */
.nzp-btn--nav {
  padding: var(--space-2) var(--space-4);
  font-size: var(--fs-sm);
  font-weight: 600;
  color: var(--color-secondary);
  border: 1px solid var(--color-secondary);
  border-radius: var(--radius);
  text-decoration: none;
  white-space: nowrap;
  transition: background var(--transition), color var(--transition);
}
.nzp-btn--nav:hover { background: var(--color-secondary); color: var(--color-primary); }

/* Below 1024px the header runs out of room; the CTA moves into the menu. */
@media (max-width: 1024px) {
  .nzp-header .nzp-btn--nav { display: none; }
}
.nzp-nav__cta { display: none; }
@media (max-width: 1024px) {
  .nzp-nav__cta { display: block; padding: var(--space-4); }
  .nzp-nav__cta .nzp-btn--nav { display: inline-block; }
}


/* ==========================================================================
   26. KEY FACTS CARDS (with photography)
   ========================================================================== */

.nzp-kpi--photo { padding: 0; overflow: hidden; display: flex; flex-direction: column; }
.nzp-kpi__media {
  aspect-ratio: 16 / 9;
  overflow: hidden;
  background: var(--color-light-dark);
}
.nzp-kpi__media img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: transform 500ms ease, filter 300ms ease;
  filter: saturate(0.85);
}
.nzp-kpi--photo:hover .nzp-kpi__media img { transform: scale(1.07); filter: saturate(1); }
.nzp-kpi__body { padding: var(--space-5) var(--space-4); flex: 1; }
.nzp-kpi--photo:hover { box-shadow: var(--shadow-lg); }


/* ==========================================================================
   27. ASSET MANAGEMENT — CROSSFADING BACKGROUND
   ========================================================================== */

.nzp-am {
  position: relative;
  overflow: hidden;
  color: var(--color-text-invert);
  padding-top: var(--space-8);
  padding-bottom: var(--space-8);
  background: var(--color-primary);
}

/* Both images are stacked; opacity is swapped for the crossfade. */
.nzp-am__bg {
  position: absolute;
  inset: 0;
  background-size: cover;
  background-position: center;
  transition: opacity 700ms ease;
  z-index: 0;
}
.nzp-am__bg--a { opacity: 1; }
.nzp-am__bg--b { opacity: 0; }
.nzp-am.is-hovered .nzp-am__bg--a { opacity: 0; }
.nzp-am.is-hovered .nzp-am__bg--b { opacity: 1; }

/* Dark scrim so the copy stays readable over either image. */
.nzp-am::before {
  content: '';
  position: absolute;
  inset: 0;
  z-index: 1;
  background: linear-gradient(rgba(6, 31, 17, 0.82), rgba(6, 31, 17, 0.88));
  pointer-events: none;
}
.nzp-am > .nzp-container { position: relative; z-index: 2; }

.nzp-am h2, .nzp-am h3 { color: var(--color-text-invert); }
.nzp-am .nzp-card {
  background: rgba(255, 255, 255, 0.06);
  border-color: rgba(255, 255, 255, 0.18);
  backdrop-filter: blur(2px);
}
.nzp-am .nzp-card:hover { background: rgba(255, 255, 255, 0.1); border-color: var(--color-secondary); }
.nzp-am .nzp-card p { color: rgba(255, 255, 255, 0.82); }
.nzp-am .nzp-card__badge { background: var(--color-secondary); color: var(--color-primary); }

/* Checkmark ticks instead of round bullets. */
.nzp-list--check li { padding-left: var(--space-6); }
.nzp-list--check li::before {
  content: '\2713';
  width: auto;
  height: auto;
  top: 0;
  border-radius: 0;
  background: none;
  color: var(--color-secondary);
  font-weight: 700;
  font-size: 1.05em;
  line-height: 1.6;
}


/* ==========================================================================
   28. AUTO-SCROLLING PHOTO SLIDESHOW
   ========================================================================== */

.nzp-slideshow {
  position: relative;
  overflow: hidden;
  width: 100%;
}
.nzp-slideshow__track {
  display: flex;
  gap: var(--space-4);
  width: max-content;
  animation: nzp-slide 44s linear infinite;
}
.nzp-slideshow:hover .nzp-slideshow__track { animation-play-state: paused; }

.nzp-slideshow__item {
  flex: 0 0 420px;
  aspect-ratio: 16 / 10;
  overflow: hidden;
  border-radius: var(--radius);
}
.nzp-slideshow__item img { width: 100%; height: 100%; object-fit: cover; }

@keyframes nzp-slide {
  from { transform: translateX(0); }
  to   { transform: translateX(-50%); }
}

@media (max-width: 768px) {
  .nzp-slideshow__item { flex-basis: 260px; }
}


/* ==========================================================================
   29. TRACK RECORD BAR CHART
   ========================================================================== */

.nzp-chart { display: flex; flex-direction: column; gap: var(--space-3); }

.nzp-chart__row {
  display: grid;
  grid-template-columns: 92px 1fr;
  align-items: center;
  gap: var(--space-4);
}
.nzp-chart__label {
  font-size: var(--fs-sm);
  font-weight: 600;
  color: var(--color-text-muted);
  text-align: right;
  white-space: nowrap;
}
.nzp-chart__bar-wrap { position: relative; display: flex; align-items: center; gap: var(--space-3); }

.nzp-chart__bar {
  height: 30px;
  border-radius: 0 3px 3px 0;
  background: var(--color-primary);
  transition: width 900ms cubic-bezier(0.22, 1, 0.36, 1), background var(--transition);
  min-width: 3px;
}
.nzp-chart__row:hover .nzp-chart__bar { background: var(--color-primary-90); }

/* The final bar is a forward target, not an achieved figure. */
.nzp-chart__bar--target {
  background: transparent;
  border: 2px dotted var(--color-secondary);
  border-left: 0;
}
.nzp-chart__value {
  font-size: var(--fs-sm);
  font-weight: 700;
  color: var(--color-primary);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}
.nzp-chart__value--target { color: var(--color-gold-dark); }

.nzp-chart-legend {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-5);
  margin-top: var(--space-6);
  font-size: var(--fs-sm);
  color: var(--color-text-muted);
}
.nzp-chart-legend span { display: inline-flex; align-items: center; gap: var(--space-2); }
.nzp-chart-legend i { width: 22px; height: 12px; display: inline-block; border-radius: 2px; }

@media (max-width: 768px) {
  .nzp-chart__row { grid-template-columns: 70px 1fr; gap: var(--space-3); }
  .nzp-chart__label { font-size: var(--fs-xs); }
}


/* ==========================================================================
   30. ESG PILLAR ACCORDION
   ========================================================================== */

.nzp-pillar {
  border: 1px solid var(--color-border);
  border-radius: var(--radius-lg);
  background: var(--color-bg);
  margin-bottom: var(--space-4);
  overflow: hidden;
  transition: border-color var(--transition), box-shadow var(--transition);
}
.nzp-pillar.is-open { border-color: var(--color-secondary); box-shadow: var(--shadow); }

.nzp-pillar__trigger {
  display: flex;
  align-items: center;
  gap: var(--space-4);
  width: 100%;
  padding: var(--space-5) var(--space-6);
  background: none;
  border: 0;
  cursor: pointer;
  text-align: left;
  font-family: var(--font-sans);
  font-size: var(--fs-lg);
  font-weight: 600;
  color: var(--color-primary);
}
.nzp-pillar__trigger:hover { background: var(--color-bg-alt); }

.nzp-pillar__icon { width: 40px; height: 40px; flex: 0 0 40px; }
.nzp-pillar__icon svg { width: 100%; height: 100%; stroke: var(--color-secondary); fill: none; stroke-width: 1.6; }

/* Gentle pulse so the icons read as live without being distracting. */
.nzp-pillar__icon { animation: nzp-icon-pulse 3.2s ease-in-out infinite; }
.nzp-pillar:nth-child(2) .nzp-pillar__icon { animation-delay: 0.5s; }
.nzp-pillar:nth-child(3) .nzp-pillar__icon { animation-delay: 1s; }

@keyframes nzp-icon-pulse {
  0%, 100% { transform: scale(1);    opacity: 0.9; }
  50%      { transform: scale(1.08); opacity: 1; }
}

.nzp-pillar__chevron { margin-left: auto; transition: transform var(--transition); color: var(--color-secondary); font-size: 1.2em; }
.nzp-pillar.is-open .nzp-pillar__chevron { transform: rotate(180deg); }

.nzp-pillar__panel {
  display: none;
  padding: 0 var(--space-6) var(--space-6);
}
.nzp-pillar.is-open .nzp-pillar__panel { display: block; }

/* Collapsed pillars keep only their heading, so the row stays tidy. */
.nzp-pillar:not(.is-open) .nzp-pillar__trigger > span:nth-of-type(1) { font-size: var(--fs-lg); }
.nzp-pillar__panel > p:first-child { margin-top: 0; }


/* ==========================================================================
   31. SDG CAROUSEL
   ========================================================================== */

.nzp-sdg-carousel { position: relative; padding: var(--space-7) 0; overflow: hidden; }

/* The dotted rail the cards travel along. */
.nzp-sdg-carousel::before {
  content: '';
  position: absolute;
  left: 0;
  right: 0;
  top: 50%;
  border-top: 2px dotted var(--color-secondary);
  opacity: 0.55;
}

/* Cards stretch to a common height rather than centring at their own. */
.nzp-sdg-carousel__track {
  display: flex;
  align-items: stretch;
  gap: var(--space-5);
  width: max-content;
  animation: nzp-sdg-scroll 38s linear infinite;
  position: relative;
}
.nzp-sdg-carousel:hover .nzp-sdg-carousel__track { animation-play-state: paused; }

@keyframes nzp-sdg-scroll {
  from { transform: translateX(0); }
  to   { transform: translateX(-50%); }
}

.nzp-sdg-card {
  /*
   * Sized so no more than three are ever in view at once. At a fixed 320px,
   * five sat in frame on a wide screen and each was too small to read.
   */
  /*
   * Width comes from the viewport with no upper cap. A fixed ceiling is what
   * put five or six in frame on a wide monitor: at 2560px a 430px card leaves
   * room for six. At roughly a third of the viewport the count holds at three
   * whatever the screen width.
   */
  flex: 0 0 max(290px, 30vw);
  background: var(--color-bg);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow);
  overflow: hidden;
}
.nzp-sdg-card__band {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  padding: var(--space-4) var(--space-5);
  color: #FFFFFF;
}
.nzp-sdg-card__num { font-size: var(--fs-2xl); font-weight: 700; line-height: 1; }
.nzp-sdg-card__name { font-size: var(--fs-sm); font-weight: 700; line-height: 1.25; text-transform: uppercase; letter-spacing: 0.04em; }
.nzp-sdg-card__body { padding: var(--space-5); }
.nzp-sdg-card__body p { font-size: var(--fs-sm); color: var(--color-text-muted); margin: 0; }


/* ==========================================================================
   32. STRATEGY DIAGONAL LAYOUT
   ========================================================================== */

.nzp-diagonal {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: var(--space-5);
}
/* Staircase: block, image, block, image, block — descending left to right. */
.nzp-diagonal__block--1 { grid-column: 1; grid-row: 1; }
.nzp-diagonal__img--tr  { grid-column: 3; grid-row: 1; }
.nzp-diagonal__block--2 { grid-column: 2; grid-row: 2; }
.nzp-diagonal__block--3 { grid-column: 3; grid-row: 3; }
.nzp-diagonal__img--bl  { grid-column: 1; grid-row: 3; }

.nzp-diagonal__img {
  overflow: hidden;
  border-radius: var(--radius-lg);
  min-height: 220px;
}
.nzp-diagonal__img img { width: 100%; height: 100%; object-fit: cover; }

@media (max-width: 768px) {
  .nzp-diagonal { grid-template-columns: 1fr; }
  .nzp-diagonal > * { grid-column: 1 !important; grid-row: auto !important; }
  .nzp-diagonal__img { min-height: 180px; }
}


/* ==========================================================================
   33. REMSCHEID BEFORE / AFTER
   ========================================================================== */

/*
 * Before / after aerials.
 *
 * `align-items: start` pins both figures to the top of the row. The supplied
 * "after" photograph is taller than the "before" (it carries the Heat pumps
 * and Solar Panels annotations beneath it), and without this the shorter
 * image would be centred against the taller one and the roof lines would not
 * line up.
 *
 * The fixed aspect ratio is also removed here: cropping to a set ratio would
 * cut those annotations off the bottom of the "after" image.
 */
.nzp-ba-photos {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--space-5);
  margin-bottom: var(--space-6);
  align-items: start;
}
.nzp-ba-photos figure { margin: 0; }
/* Both frames share one ratio so the roof lines align. The "after" image
   carries annotation text along its bottom edge, so it is anchored to the
   top of the frame and the strip is cropped away. */
.nzp-ba-photos .nzp-photo-frame { aspect-ratio: 3 / 2; height: auto; }
.nzp-ba-photos .nzp-photo-frame img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center top;
}

/*
 * The source aerials are flat and grey. A light grade lifts them without
 * looking processed: more saturation, a touch more contrast, slightly warmer.
 */
.nzp-ba-photos .nzp-photo-frame img {
  filter: saturate(1.45) contrast(1.10) brightness(1.06);
  transition: filter var(--transition);
}
.nzp-ba-photos figure:hover .nzp-photo-frame img {
  filter: saturate(1.6) contrast(1.14) brightness(1.08);
}

.nzp-ba-photos figcaption {
  margin-top: var(--space-2);
  font-size: var(--fs-xs);
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--color-text-muted);
  font-style: normal;
}

/* Annotation labels beneath the "after" photo, as on the source slide. */
.nzp-ba-annotations {
  display: flex;
  justify-content: space-between;
  gap: var(--space-4);
  margin-top: var(--space-2);
  font-size: var(--fs-sm);
  font-weight: 600;
  color: var(--color-secondary);
}

/*
 * EPC rating chip — the arrow-tipped badge used on energy labels.
 * The notch is cut with clip-path so it needs no extra markup.
 */
.nzp-epc-badge {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 62px;
  padding: var(--space-2) var(--space-4) var(--space-2) var(--space-3);
  clip-path: polygon(0 0, calc(100% - 12px) 0, 100% 50%, calc(100% - 12px) 100%, 0 100%);
  color: #FFFFFF;
  font-weight: 700;
  font-size: var(--fs-md);
  line-height: 1;
  letter-spacing: 0.02em;
}
.nzp-epc-badge--e { background: #D9534F; }
.nzp-epc-badge--c { background: #F0A030; }
.nzp-epc-badge--a { background: #7DC242; }

/* Column headers on the metrics table, per the slide. */
.nzp-metrics thead th:not(:first-child) { text-align: center; }
.nzp-metrics tbody td { text-align: center; }
.nzp-metrics tbody th { text-align: left; }

.nzp-metrics { width: 100%; border-collapse: collapse; font-size: var(--fs-sm); }
.nzp-metrics th, .nzp-metrics td { padding: var(--space-3); text-align: left; border-bottom: 1px solid var(--color-border); }
.nzp-metrics thead th {
  font-size: var(--fs-xs);
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--color-text-muted);
  border-bottom: 2px solid var(--color-secondary);
}
.nzp-metrics tbody th { font-weight: 600; color: var(--color-primary); }
.nzp-metrics td { font-variant-numeric: tabular-nums; }
.nzp-metrics .is-final { font-weight: 700; color: var(--color-pv); }

.nzp-table-scroll { overflow-x: auto; }

@media (max-width: 768px) {
  .nzp-ba-photos { grid-template-columns: 1fr; }
}


/* ==========================================================================
   34. INVESTOR ARTICLE CARDS
   ========================================================================== */

.nzp-article-grid { display: grid; grid-template-columns: repeat(2, 1fr); gap: var(--space-5); }

.nzp-article-card {
  display: flex;
  flex-direction: column;
  background: var(--color-bg);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-lg);
  overflow: hidden;
  transition: transform var(--transition), box-shadow var(--transition);
}
.nzp-article-card:hover { transform: translateY(-3px); box-shadow: var(--shadow); }
.nzp-article-card__media {
  aspect-ratio: 16 / 9;
  background: var(--color-light-dark);
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--color-text-muted);
  font-size: var(--fs-xs);
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}
.nzp-article-card__media img { width: 100%; height: 100%; object-fit: cover; }
.nzp-article-card__body { padding: var(--space-5); display: flex; flex-direction: column; flex: 1; }
.nzp-article-card__date {
  font-size: var(--fs-xs);
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--color-secondary);
  margin-bottom: var(--space-2);
}
.nzp-article-card__title { font-size: var(--fs-md); margin-bottom: var(--space-4); flex: 1; }

@media (max-width: 768px) { .nzp-article-grid { grid-template-columns: 1fr; } }


/* ==========================================================================
   35. PRESS CARD IMAGERY
   ========================================================================== */

.nzp-press-card { padding: 0; overflow: hidden; border-left-width: 3px; }
.nzp-press-card__media { aspect-ratio: 16 / 9; overflow: hidden; background: var(--color-light-dark); }
.nzp-press-card__media img { width: 100%; height: 100%; object-fit: cover; transition: transform 500ms ease; }
.nzp-press-card:hover .nzp-press-card__media img { transform: scale(1.05); }
.nzp-press-card__body { padding: var(--space-5); display: flex; flex-direction: column; flex: 1; }

/* Simple intro line at the top of the Press page — no banner, no dark band. */
.nzp-page-intro {
  font-size: var(--fs-md);
  color: var(--color-text-muted);
  margin-bottom: var(--space-7);
}


/* ==========================================================================
   36. CONTACT WATERMARK
   ========================================================================== */

.nzp-contact-wrap { position: relative; }
.nzp-contact-watermark {
  position: absolute;
  left: -6%;
  top: 50%;
  transform: translateY(-50%);
  width: 420px;
  max-width: 42vw;
  opacity: 0.08;
  pointer-events: none;
  user-select: none;
  z-index: 0;
}
.nzp-contact-wrap > .nzp-contact-grid { position: relative; z-index: 1; }

@media (max-width: 768px) {
  .nzp-contact-watermark { display: none; }
}


/* ==========================================================================
   37. FOOTER — HORIZONTAL COMPACT
   ========================================================================== */

.nzp-footer__top {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-5);
  padding: var(--space-6) 0 var(--space-4);
}
.nzp-footer__identity { display: flex; flex-direction: column; gap: 2px; }
.nzp-footer__identity strong { color: var(--color-text-invert); font-size: var(--fs-md); }
.nzp-footer__identity span,
.nzp-footer__identity a { font-size: var(--fs-sm); }

/* Navigation runs as a single horizontal row. */
.nzp-footer__nav {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-5);
  list-style: none;
  margin: 0;
  padding: var(--space-4) 0;
  border-top: 1px solid var(--color-white-20);
  border-bottom: 1px solid var(--color-white-20);
  font-size: var(--fs-sm);
}
.nzp-footer__nav li { margin: 0; }

@media (max-width: 768px) {
  .nzp-footer__top { flex-direction: column; align-items: flex-start; gap: var(--space-4); }
  .nzp-footer__nav { gap: var(--space-4); }
}


/* ==========================================================================
   38. MANAGE TO GREEN — NUMBERED CALLOUTS
   ========================================================================== */

/* Numbered markers drawn on the building, matching the numbered steps. */
.nzp-house__marker circle { fill: rgba(255, 255, 255, 0.9); stroke: var(--color-primary); stroke-width: 1.5; }
.nzp-house__marker text {
  font-family: var(--font-sans);
  font-size: 13px;
  font-weight: 700;
  fill: var(--color-primary);
  text-anchor: middle;
}

/* The Phase 2 figure: either the uploaded render or the fallback drawing. */
.nzp-mtg-figure {
  border-radius: var(--radius-lg);
  overflow: hidden;
  box-shadow: var(--shadow);
  background: #EEF3F6;
}
.nzp-mtg-figure img,
.nzp-mtg-figure svg { display: block; width: 100%; height: auto; }

/* Step number in a dashed ring, per the presentation layout. */
.nzp-step-num {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 44px;
  height: 44px;
  flex: 0 0 44px;
  border-radius: 50%;
  border: 2px dashed var(--color-secondary);
  font-weight: 700;
  color: var(--color-primary);
}
.nzp-step {
  display: flex;
  align-items: flex-start;
  gap: var(--space-4);
  margin-bottom: var(--space-5);
}
.nzp-step__title { display: block; font-weight: 700; margin-bottom: var(--space-1); }
.nzp-step__text  { display: block; font-size: var(--fs-sm); color: var(--color-text-muted); }


/* ==========================================================================
   40. REFINEMENTS
   ========================================================================== */

/* --- Video header: no solid black bar ------------------------------------
   The overlay used to be an opaque band across the middle, which read as an
   ugly slab. It is now a full-height gradient scrim, so the video stays
   visible and the text is lifted by weight and shadow instead. */
.nzp-page-header--video { height: 320px; }
.nzp-page-header__overlay {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  background: linear-gradient(
    to bottom,
    rgba(6, 31, 17, 0.55) 0%,
    rgba(6, 31, 17, 0.28) 45%,
    rgba(6, 31, 17, 0.62) 100%
  );
  padding: 0;
}
.nzp-page-header__subtitle {
  font-family: var(--font-display);
  font-size: clamp(1.5rem, 2.8vw, 2.3rem);
  font-weight: 600;
  line-height: 1.3;
  max-width: 900px;
  margin: 0 auto;
  color: #FFFFFF;
  /* Shadow alone; the stroke read as an outline effect at this size. */
  -webkit-text-stroke: 0;
  text-shadow:
    0 2px 3px rgba(6, 31, 17, 1),
    0 4px 10px rgba(6, 31, 17, 0.95),
    0 8px 34px rgba(6, 31, 17, 0.9),
    0 0 3px rgba(6, 31, 17, 1);
}

/* Headings on dark sections get the same treatment. */
.nzp-section--dark h2,
.nzp-am h2,
.nzp-hero-copy h2 {
  color: #FFFFFF;
  text-shadow:
    0 2px 4px rgba(6, 31, 17, 0.95),
    0 5px 14px rgba(6, 31, 17, 0.8),
    0 10px 36px rgba(6, 31, 17, 0.7);
}

/* --- Key Facts: six cards, three across ---------------------------------- */
.nzp-kpi-grid { grid-template-columns: repeat(3, 1fr); gap: var(--space-5); }

.nzp-kpi__media { aspect-ratio: 16 / 9; display: flex; align-items: center; justify-content: center; }

/* Germany map inside a Key Fact card. */
.nzp-kpi__map {
  width: 100%;
  height: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--color-bg-alt);
  padding: var(--space-2);
}
.nzp-kpi__map svg { height: 100%; width: auto; max-height: 150px; }

/* EPC scale graphic inside a Key Fact card. */
.nzp-kpi__graphic {
  width: 100%;
  height: 100%;
  object-fit: contain;
  background: var(--color-bg-alt);
  padding: var(--space-3);
}

/* Drawn mark for facts with no natural photograph. */
.nzp-kpi__mark {
  width: 100%;
  height: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--color-primary);
  color: var(--color-secondary);
}
.nzp-kpi__mark svg { width: 68px; height: 68px; }

/* Neutral panel for facts with no photograph yet. */
.nzp-kpi__empty {
  width: 100%;
  height: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--color-light-dark);
  border-bottom: 1px solid var(--color-border);
  color: #A9B3AE;
}
.nzp-kpi__empty svg { width: 54px; height: 54px; }

/* EPC card: the NZP mark sits beside the rating scale. */
.nzp-kpi__epc {
  width: 100%;
  height: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-3);
  padding: var(--space-3);
  background: var(--color-bg-alt);
}
/* Up ~30% so it sits comfortably against its neighbours. */
.nzp-kpi__epc svg { width: 100%; height: 100%; max-height: 195px; }

/* Map card: outline plus the region list beside it. */
.nzp-kpi__map-wrap {
  width: 100%;
  height: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-3);
  padding: var(--space-2) var(--space-3);
  background: var(--color-bg-alt);
  overflow: hidden;
}
.nzp-kpi__map { background: none; padding: 0; flex: 0 0 auto; width: auto; height: 100%; display: flex; align-items: center; }
.nzp-kpi__map svg { max-height: 132px; width: auto; }
.nzp-kpi__map-key {
  list-style: none;
  margin: 0;
  padding: 0;
  font-size: 10px;
  line-height: 1.45;
  text-align: left;
  flex: 0 1 auto;
  min-width: 0;
}
.nzp-kpi__map-key li { display: flex; align-items: center; gap: 6px; margin: 0 0 3px; color: var(--color-text-muted); }
.nzp-kpi__map-key i { width: 9px; height: 9px; border-radius: 2px; flex: 0 0 9px; }

/* --- Overview: slideshow beside the copy --------------------------------- */
.nzp-text-media {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  gap: var(--space-8);
  align-items: center;
}
/* Both columns must be allowed to shrink. Without min-width:0 the column
   holding the marquee expands to the width of every slide combined. */
.nzp-text-media > * { min-width: 0; }
/* Vertical variant of the scrolling strip, sized to sit beside a text block. */
.nzp-slideshow--panel {
  border-radius: var(--radius-lg);
  overflow: hidden;
  box-shadow: var(--shadow);
  max-width: 100%;
}
/* Fixed pixel width — a percentage basis resolves against the max-content
   track and produces a single enormous slide. */
.nzp-slideshow--panel .nzp-slideshow__item {
  /*
   * A FIXED pixel width, not a percentage. The track is width:max-content, so
   * a percentage basis resolves against the whole track and collapses the
   * strip into one enormous slide - which is exactly what happened when this
   * was briefly set to 100%.
   */
  flex: 0 0 400px;
  width: 400px;
  aspect-ratio: 4 / 3;
}
.nzp-slideshow--panel .nzp-slideshow__track { animation-duration: 34s; }

/* --- ESG pillars: horizontal on desktop ---------------------------------- */
/* Horizontal accordion: the open pillar grows and the other two shrink
   beside it, instead of pushing a tall panel down the page. */
.nzp-accordion { display: flex; gap: var(--space-4); align-items: stretch; }
.nzp-pillar { flex: 1 1 0; min-width: 0; transition: flex-grow 320ms ease; }
.nzp-pillar.is-open { flex-grow: 2.6; }
.nzp-pillar { margin-bottom: 0; display: flex; flex-direction: column; }
.nzp-pillar__trigger {
  flex-direction: column;
  align-items: flex-start;
  gap: var(--space-3);
  text-align: left;
  padding: var(--space-6);
}
.nzp-pillar__trigger > span:nth-of-type(1) { font-size: var(--fs-xl); }
.nzp-pillar__icon { width: 52px; height: 52px; flex: 0 0 52px; }
.nzp-pillar__chevron { margin-left: 0; align-self: flex-start; }
.nzp-pillar__panel { padding: 0 var(--space-6) var(--space-6); }

/* --- SDG cards: three only, larger, hover highlights and stops ------------ */
.nzp-sdg-carousel { padding: var(--space-8) 0; }
/* The cards travel left to right again, widely spaced. */
.nzp-sdg-carousel__track { gap: var(--space-9); }

.nzp-sdg-card {
  /* Width is inherited from the viewport-relative rule above; a fixed value
     here overrode it and reinstated the too-many-in-frame problem. */
  display: flex;
  flex-direction: column;
  transition: transform var(--transition), box-shadow var(--transition), outline-color var(--transition);
  outline: 3px solid transparent;
  outline-offset: 4px;
}
.nzp-sdg-card:hover,
.nzp-sdg-card:focus-within {
  transform: translateY(-6px);
  box-shadow: var(--shadow-lg);
  outline-color: var(--color-secondary);
}
/*
 * A fixed band height. "Industry, Innovation and Infrastructure" wraps to two
 * lines while the other two names fit on one, so the coloured band - and with
 * it the whole card - grew taller on that goal alone. Reserving the two-line
 * height for every band keeps the three identical whatever the name length.
 */
.nzp-sdg-card__band {
  padding: var(--space-5) var(--space-6);
  gap: var(--space-4);
  min-height: 116px;
}
.nzp-sdg-card__num { font-size: 3rem; }

/* Drawn goal icon, in the goal's own colour band. */
.nzp-sdg-card__icon { width: 46px; height: 46px; flex: 0 0 46px; }
.nzp-sdg-card__icon svg { width: 100%; height: 100%; fill: none; stroke: currentColor; stroke-width: 1.8; }
.nzp-sdg-card__body { padding: var(--space-6); flex: 1; }
.nzp-sdg-card__body p { font-size: var(--fs-base); }

/* --- Track record chart: richer treatment -------------------------------- */
.nzp-chart {
  gap: var(--space-2);
  padding: var(--space-6);
  background: var(--color-bg);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-sm);
}
.nzp-chart__row {
  grid-template-columns: 96px 1fr;
  padding: var(--space-2) 0;
  border-radius: var(--radius);
  transition: background var(--transition);
}
.nzp-chart__row:hover { background: var(--color-bg-alt); }

/* Gradient fill and a subtle sheen so the bars read as designed, not default. */
.nzp-chart__bar {
  height: 34px;
  border-radius: 0 4px 4px 0;
  background: linear-gradient(90deg, #061F11 0%, #2E5B44 60%, #4C7C5D 100%);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.18);
  position: relative;
}
.nzp-chart__row:hover .nzp-chart__bar { filter: brightness(1.15); }
.nzp-chart__bar--target {
  background: repeating-linear-gradient(
    135deg,
    rgba(219, 174, 149, 0.30) 0 10px,
    rgba(219, 174, 149, 0.10) 10px 20px
  );
  border: 2px dashed var(--color-secondary);
  border-left: 0;
  box-shadow: none;
}
.nzp-chart__value { font-size: var(--fs-base); }

/* Faint vertical gridlines behind the bars. */
.nzp-chart__bar-wrap::before {
  content: '';
  position: absolute;
  inset: 0 0 0 0;
  background-image: repeating-linear-gradient(
    90deg, var(--color-border) 0 1px, transparent 1px 25%
  );
  opacity: 0.5;
  pointer-events: none;
}
.nzp-chart__bar,
.nzp-chart__value { position: relative; z-index: 1; }

/* --- Strategy diagonal: wider blocks, images fill their cell -------------- */
.nzp-diagonal { grid-template-columns: repeat(6, 1fr); gap: var(--space-5); }
.nzp-diagonal__block--1 { grid-column: 1 / span 3; grid-row: 1; }
.nzp-diagonal__img--tr  { grid-column: 4 / span 3; grid-row: 1; }
.nzp-diagonal__block--2 { grid-column: 2 / span 4; grid-row: 2; }
.nzp-diagonal__block--3 { grid-column: 4 / span 3; grid-row: 3; }
.nzp-diagonal__img--bl  { grid-column: 1 / span 3; grid-row: 3; }
/*
 * Every cell in the staircase is the same height, so "Two-Phase Program" and
 * "Oversight and Execution" match. Previously the image cells were min-height
 * 100%, which let the bottom-left photograph stretch its whole row and made
 * the two text blocks visibly different sizes.
 */
.nzp-diagonal__img { height: 260px; min-height: 260px; }

/* Graphic cells hold an SVG, not a cropped photo: contain it and let it
   size from its own aspect ratio instead of stretching to the cell. */
.nzp-diagonal__img--graphic {
  background: var(--color-bg-alt);
  display: flex;
  align-items: center;
  justify-content: center;
  padding: var(--space-5);
  min-height: 240px;
}
.nzp-diagonal__img--graphic img {
  width: 100%;
  height: auto;
  object-fit: contain;
}
.nzp-diagonal .nzp-card {
  display: flex;
  flex-direction: column;
  justify-content: center;
  min-height: 240px;
}
.nzp-diagonal .nzp-card p { font-size: var(--fs-sm); }

/* --- Remscheid metric icons ---------------------------------------------- */
.nzp-metric-label { display: flex; align-items: center; gap: var(--space-3); }
.nzp-metric-icon {
  width: 30px;
  height: 30px;
  flex: 0 0 30px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border-radius: 50%;
  background: var(--color-secondary-20);
}
.nzp-metric-icon svg { width: 18px; height: 18px; stroke-width: 1.9; fill: none; }

/* --- Press page title ----------------------------------------------------- */
.nzp-press-heading {
  font-family: var(--font-display);
  font-size: clamp(1.6rem, 3vw, 2.4rem);
  font-weight: 400;
  color: var(--color-primary);
  max-width: 24ch;
  margin: 0 0 var(--space-3);
}
.nzp-press-heading + hr { margin-top: 0; }

/* --- Contact: identity beside the form, not stacked above ---------------- */
.nzp-contact-layout {
  display: grid;
  grid-template-columns: 300px minmax(0, 1fr);
  gap: var(--space-8);
  align-items: start;
}
.nzp-contact-aside { text-align: center; }
.nzp-contact-aside h1 { font-size: var(--fs-2xl); margin-bottom: var(--space-3); }

/* The NZP mark sits inside the envelope rather than beneath it. */
/*
 * The mark is part of the drawing now, so the absolutely-positioned overlay
 * and the stroke-only envelope styling above are both retired for this block.
 */
.nzp-envelope-mark { width: 240px; max-width: 100%; margin: 0 auto var(--space-5); }
.nzp-envelope-mark .nzp-envelope {
  width: 100%;
  height: auto;
  margin: 0;
  display: block;
  stroke: none;
  fill: none;
  stroke-width: 0;
}

/* Give Contact Form 7 the full column width. */
.nzp-contact-grid .wpcf7 { width: 100%; }
.nzp-contact-grid .wpcf7 input[type="text"],
.nzp-contact-grid .wpcf7 input[type="email"],
.nzp-contact-grid .wpcf7 textarea { width: 100%; }
.nzp-contact-grid .wpcf7 p { margin-bottom: var(--space-4); }

@media (max-width: 900px) {
  .nzp-contact-layout { grid-template-columns: 1fr; gap: var(--space-6); }
  .nzp-accordion { grid-template-columns: 1fr; gap: var(--space-4); }
  .nzp-text-media { grid-template-columns: 1fr; gap: var(--space-6); }
  .nzp-kpi-grid { grid-template-columns: repeat(2, 1fr); }
}


/* ==========================================================================
   39. RESPONSIVE OVERRIDES FOR THE NEW COMPONENTS
   ========================================================================== */

@media (max-width: 768px) {
  /* Hero video shrinks to a 300px band on phones. */
  .nzp-hero-video { height: 300px; }
  .nzp-page-header--video { height: 200px; }
  .nzp-page-header__subtitle { font-size: var(--fs-md); }
  .nzp-hero-copy { padding: var(--space-7) 0; }
  .nzp-logo-animation { height: 40px; width: 40px; }

  .nzp-kpi-grid { grid-template-columns: 1fr; }

  /* Three SDG cards stack and scroll horizontally instead of shrinking. */
  .nzp-sdg-carousel { overflow-x: hidden; }
  .nzp-sdg-carousel__track { justify-content: flex-start; gap: var(--space-5); }
  .nzp-sdg-card { flex: 0 0 84vw; }

  .nzp-slideshow--panel .nzp-slideshow__item { flex-basis: 300px; width: 300px; aspect-ratio: 16 / 10; }
}


/* ==========================================================================
   23. PRINT
   ========================================================================== */

@media print {
  .nzp-header,
  .nzp-footer,
  .nzp-nav-toggle,
  .nzp-carousel { display: none !important; }
  .nzp-site-content { padding-top: 0; }
  body { color: #000; background: #fff; }
  a[href]::after { content: ' (' attr(href) ')'; font-size: 0.85em; }
}


/* ==========================================================================
   41. INSTITUTIONAL TYPOGRAPHY, MAP, LOGIN AND ESG
   ========================================================================== */

/* --- #3 / #10: heading face -----------------------------------------------
   Playfair read as editorial rather than institutional. Archivo is a
   grotesque with a tall x-height and tight apertures, closer to how fund
   factsheets set their headings. Licensed under the SIL Open Font License,
   so it is free for commercial use. */
:root {
  --font-display: 'Archivo', 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
}

h1, h2, h3,
.nzp-press-heading,
.nzp-page-header__subtitle {
  font-family: var(--font-display);
  font-weight: 700;
  letter-spacing: -0.015em;
}

/* Every page-header subtitle: white, heavy, and lifted off the video. */
/*
 * Needs to outrank `.nzp-page-header p` (0,1,1) further up the sheet, which
 * paints these sand. A bare class (0,1,0) lost, which is why the change only
 * appeared on the homepage - that heading is an h1, not a p.
 */
.nzp-page-header p.nzp-page-header__subtitle,
.nzp-page-header__subtitle {
  color: #FFFFFF;
  font-weight: 700;
  letter-spacing: -0.02em;
  -webkit-text-stroke: 0;
  text-shadow:
    0 1px 2px rgba(6, 31, 17, 0.95),
    0 4px 16px rgba(6, 31, 17, 0.75),
    0 12px 44px rgba(6, 31, 17, 0.55);
}

/* --- #1: framed divider between the hero video and the copy band --------- */
/*
 * A hairline, not a band. The previous version padded 1.5rem top and bottom
 * over a solid brand-green fill, which read as a thick green stripe wedged
 * between the video and the photograph rather than as a join between them.
 */
.nzp-frame-divider {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  padding: 0 8vw;
  /* 14px of brand green rather than the previous ~50px slab. It keeps the
     join dark so no page background shows through between the two bands. */
  height: 14px;
  background: var(--color-primary);
}
.nzp-frame-divider__line {
  flex: 1;
  height: 1px;
  background: linear-gradient(90deg, transparent, rgba(219, 174, 149, 0.85), transparent);
}
.nzp-frame-divider__mark {
  width: 7px;
  height: 7px;
  flex: 0 0 7px;
  transform: rotate(45deg);
  border: 1px solid var(--color-secondary);
  background: var(--color-primary);
}

/* --- #2: the hero photograph drifts instead of sitting frozen ------------ */
.nzp-hero-copy { position: relative; overflow: hidden; }
.nzp-hero-copy__bg {
  position: absolute;
  /* Oversized so the drift never exposes an edge. */
  inset: -6% -8%;
  background-size: cover;
  background-position: center;
  animation: nzp-drift 34s ease-in-out infinite alternate;
  will-change: transform;
  /*
   * Explicitly the bottom layer. Moving the photograph onto its own element
   * made it a real child, and a real child paints above the ::before scrim
   * that keeps the copy readable, so the scrim was being covered by the very
   * image it was meant to darken. These three z-indexes pin the order:
   * photograph, then scrim, then text.
   */
  z-index: 0;
}
.nzp-hero-copy::before { z-index: 1; }
.nzp-hero-copy > .nzp-container { z-index: 2; }
@keyframes nzp-drift {
  from { transform: translate3d(-1.6%, -1%, 0) scale(1.06); }
  to   { transform: translate3d( 1.6%,  1%, 0) scale(1.10); }
}
@media (prefers-reduced-motion: reduce) {
  .nzp-hero-copy__bg { animation: none; }
}

/* --- #8: Natural Earth country outlines ---------------------------------- */
.nzp-map--office { max-width: 860px; }
.nzp-map--office .nzp-country {
  fill: rgba(255, 255, 255, 0.13);
  stroke: rgba(255, 255, 255, 0.30);
  stroke-width: 1.1;
  stroke-linejoin: round;
  transition: fill var(--transition);
}
.nzp-map--office .nzp-country.is-office {
  stroke: rgba(255, 255, 255, 0.85);
  stroke-width: 1.6;
}
.nzp-pin__dot { fill: #FFFFFF; }
.nzp-pin__label { font-size: 17px; }

/* --- #11: Germany map interaction and density --------------------------- */
/* Clicking a state used to leave a black focus rectangle. Suppress the UA
   outline and show a brand ring instead. */
.nzp-map--germany path { outline: none; cursor: default; }
.nzp-map--germany path:focus,
.nzp-map--germany path:focus-visible,
.nzp-map--germany path::-moz-focus-inner {
  outline: none;
  border: 0;
}
.nzp-map--germany path.is-active { stroke: var(--color-primary); stroke-width: 3; }

.nzp-region-star { fill: var(--color-secondary); stroke: var(--color-primary); stroke-width: 1.4; }
.nzp-region-star__label {
  font-family: var(--font-sans);
  font-size: 15px;
  font-weight: 700;
  fill: var(--color-primary);
  paint-order: stroke;
  stroke: #FFFFFF;
  stroke-width: 3.5px;
}

/* Share-of-area donut beside the legend. */
.nzp-pie { display: block; margin: 0 auto var(--space-5); max-width: 320px; }
.nzp-pie__leader {
  fill: none;
  stroke: var(--color-text-muted);
  stroke-width: 1.4;
  stroke-dasharray: 2 3;
}
.nzp-pie__callout {
  font-family: var(--font-sans);
  font-size: 15px;
  font-weight: 700;
  fill: var(--color-primary);
}
.nzp-pie__hole-label {
  font-family: var(--font-sans);
  font-size: 13px;
  font-weight: 700;
  fill: var(--color-primary);
  text-anchor: middle;
}
.nzp-pie__slice { transition: opacity var(--transition); }
.nzp-pie:hover .nzp-pie__slice { opacity: 0.55; }
.nzp-pie__slice:hover { opacity: 1; }

/* --- #10: slideshow frames instead of faded edges and white gaps -------- */
.nzp-slideshow::before,
.nzp-slideshow::after { display: none; }
.nzp-slideshow--panel { background: var(--color-primary); }
.nzp-slideshow--panel .nzp-slideshow__track { gap: 0; }
.nzp-slideshow--panel .nzp-slideshow__item {
  padding: 0;
  /* A brand rule divides each frame, rather than a white gutter. */
  border-right: 3px solid var(--color-secondary);
}
.nzp-slideshow--panel .nzp-slideshow__item img {
  border-radius: 0;
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* --- #13/#15: equal-weight blocks on the Strategy staircase ------------- */
.nzp-section-head--wide { max-width: none; }
.nzp-section-head--wide p { max-width: none; }
.nzp-diagonal .nzp-card { min-height: 260px; }
.nzp-diagonal__img--graphic { min-height: 260px; }

/* --- #19: ESG as three intersecting circles ----------------------------- */
.nzp-venn {
  position: relative;
  width: 100%;
  max-width: 760px;
  margin: 0 auto;
  aspect-ratio: 1 / 0.92;
}
.nzp-venn__svg { width: 100%; height: 100%; overflow: visible; }
.nzp-venn__ring {
  fill: transparent;
  stroke-width: 4;
  transition: fill var(--transition), stroke-width var(--transition);
  cursor: pointer;
}
.nzp-venn__hit { fill: transparent; cursor: pointer; }
.nzp-venn__label {
  font-family: var(--font-display);
  font-size: 26px;
  font-weight: 700;
  text-anchor: middle;
  pointer-events: none;
}
.nzp-venn__icon { pointer-events: none; }
.nzp-venn__core { fill: #2F5FA8; }
.nzp-venn__core-label {
  font-family: var(--font-display);
  font-size: 22px;
  font-weight: 700;
  fill: #FFFFFF;
  text-anchor: middle;
  pointer-events: none;
}
.nzp-venn__group.is-active .nzp-venn__ring { fill: currentColor; fill-opacity: 0.12; stroke-width: 6; }

/* The panel floats over the diagram on hover, colour-themed per pillar. */
/*
 * Each group carries its pillar colour as `color`, so the ring tints itself
 * from currentColor and stays in step automatically. Icons and labels switch
 * to the deep brand green - colour-on-colour washed out once the circles
 * carried a fill of their own.
 */
/*
 * The fills are unchanged in hue; the ground beneath them is what moved. On a
 * near-opaque card 0.16 read as a clean tint, but against 22% glass the
 * photograph dilutes it. Raising the opacity restores the colour that was
 * there before without altering the palette.
 */
.nzp-venn__ring {
  fill: currentColor;
  fill-opacity: 0.4;
}
.nzp-venn__group:hover .nzp-venn__ring,
.nzp-venn__group.is-active .nzp-venn__ring { fill-opacity: 0.58; }
.nzp-venn__group .nzp-venn__icon { stroke: var(--color-primary); }
/*
 * A stroke on SVG text is drawn as a hard rim around every letter, which on
 * short bold words reads as an outline effect. Stacked drop-shadows give a
 * soft halo instead: the words still separate from the tinted circles, but
 * the letterforms stay clean.
 */
.nzp-venn__group .nzp-venn__label {
  fill: var(--color-primary);
  paint-order: normal;
  stroke: none;
  filter:
    drop-shadow(0 0 2px rgba(255, 255, 255, 0.95))
    drop-shadow(0 0 5px rgba(255, 255, 255, 0.75));
}

.nzp-venn-panel {
  position: absolute;
  inset: auto 0 0;
  z-index: 3;
  background: #FFFFFF;
  border-radius: var(--radius-lg);
  border-top: 6px solid currentColor;
  box-shadow: var(--shadow-lg);
  padding: var(--space-6);
  opacity: 0;
  visibility: hidden;
  transform: translateY(14px);
  transition: opacity var(--transition), transform var(--transition), visibility var(--transition);
}
.nzp-venn-panel.is-open { opacity: 1; visibility: visible; transform: translateY(0); }
.nzp-venn-panel h3 { margin-bottom: var(--space-3); color: currentColor; }
.nzp-venn-panel p,
.nzp-venn-panel li { color: var(--color-text); font-weight: 500; }
.nzp-venn-panel p:last-child { margin-bottom: 0; }

/* --- #25: partner logo carousel ----------------------------------------- */
.nzp-partner {
  flex: 0 0 210px;
  height: 130px;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: var(--space-2);
  padding: var(--space-4);
  background: #FFFFFF;
  border: 1px solid var(--color-border);
  border-radius: var(--radius);
  margin-right: var(--space-5);
}
.nzp-partner__logo {
  max-width: 150px;
  max-height: 54px;
  width: auto;
  height: auto;
  object-fit: contain;
  /* Shown in their own colours: these are recognisable institutions and the
     greyscale treatment made the wall of logos harder to read, not calmer. */
  transition: transform var(--transition);
}
.nzp-partner:hover .nzp-partner__logo { transform: scale(1.04); }
.nzp-partner__wordmark {
  font-family: var(--font-display);
  font-size: var(--fs-md);
  font-weight: 700;
  color: var(--color-primary);
}
.nzp-partner__group {
  font-size: 10px;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  color: var(--color-text-muted);
}

@media (max-width: 900px) {
  .nzp-venn { aspect-ratio: 1 / 1.1; }
  .nzp-venn__label { font-size: 18px; }
}


/* --- #24: the two-phase row reads left, centre, right ------------------- */
.nzp-phases {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(280px, 1.1fr) minmax(0, 1fr);
  gap: var(--space-6);
  /*
   * Top-aligned, so both phase headings share a baseline. Centred, the taller
   * Phase 2 column floated its heading above Phase 1's and the two sides never
   * lined up.
   */
  align-items: start;
}
/* The house is the exception: it centres against the taller of the two lists. */
.nzp-phases > .nzp-house { align-self: center; margin-left: auto; margin-right: auto; }
/*
 * The building's dotted split sits 33px left of the image's own centre (377 of
 * 820), so centring the file leaves the building 4% off the container's centre
 * line. Nudging it back by exactly that fraction puts the split under the
 * heading, which is what the eye reads as centred.
 */
.nzp-house img {
  display: block;
  width: 100%;
  height: auto;
  transform: translateX(4.02%);
}

/*
 * The explanatory copy was set in the muted grey used for captions, which is
 * too light to read comfortably at this size.
 */
.nzp-phase-step__text { color: var(--color-text); opacity: 0.92; }
.nzp-phases > * { min-width: 0; }
.nzp-phase-col h3 {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  font-size: var(--fs-lg);
  margin-bottom: var(--space-5);
}
/*
 * Both columns read left to right. The mirrored version set the Phase 2 side
 * ragged-left, which is markedly harder to read and was the "unaligned"
 * complaint. These need the same two-class specificity as the older rules
 * further up the sheet, which would otherwise keep winning.
 */
.nzp-phase-col--left { text-align: left; }
.nzp-phase-col--right { text-align: left; }
.nzp-phase-col--right h3 { justify-content: flex-start; }
.nzp-phase-col--right .nzp-phase-step { text-align: left; }

.nzp-phase-step {
  display: grid;
  grid-template-columns: 14px minmax(0, 1fr);
  gap: var(--space-3);
  align-items: start;
  margin-bottom: var(--space-5);
}
.nzp-phase-step__marker {
  width: 12px;
  height: 12px;
  margin-top: 5px;
  border-radius: 50%;
  background: var(--color-secondary);
}
.nzp-phase-step--muted .nzp-phase-step__marker { background: #9AA5A0; }
.nzp-phase-step--heatpump .nzp-phase-step__marker { background: #2F7F8C; }
.nzp-phase-step--pv .nzp-phase-step__marker { background: #3F7E44; }
/* Reads the token rather than repeating the hex, so the colour is set once. */
.nzp-phase-step--control .nzp-phase-step__marker { background: var(--color-control); }

.nzp-phase-step__title {
  display: block;
  font-weight: 700;
  color: var(--color-primary);
  margin-bottom: 2px;
  line-height: 1.35;
}
.nzp-phase-step__text {
  display: block;
  font-size: var(--fs-sm);
  color: var(--color-text-muted);
  line-height: 1.55;
}
.nzp-phase-badge {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 30px;
  height: 30px;
  flex: 0 0 30px;
  border-radius: 50%;
  font-size: var(--fs-sm);
  font-weight: 700;
  color: #FFFFFF;
}
.nzp-phase-badge--1 { background: #9AA5A0; }
.nzp-phase-badge--2 { background: var(--color-primary); }
.nzp-house svg { width: 100%; height: auto; display: block; }

@media (max-width: 900px) {
  .nzp-phases { grid-template-columns: 1fr; }
  .nzp-house { order: -1; }
}

/* --- Key Facts: green premium and mandate marks ------------------------- */
.nzp-kpi__green,
.nzp-kpi__mark {
  width: 100%;
  height: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--color-bg-alt);
  padding: var(--space-3);
}
/* Was the smallest graphic on the row by some way; up ~80%. */
.nzp-kpi__green svg { width: auto; height: 100%; max-height: 238px; }
.nzp-kpi__mark { background: var(--color-primary); color: var(--color-secondary); }
.nzp-kpi__mark svg { width: auto; height: 100%; max-height: 128px; }

/* Track Record reuses the Key Facts cards, three across. */
.nzp-kpi-grid--3 { grid-template-columns: repeat(3, 1fr); }
@media (max-width: 900px) { .nzp-kpi-grid--3 { grid-template-columns: 1fr; } }


/* ==========================================================================
   42. VALUES AND MISSION STATEMENT
   --------------------------------------------------------------------------
   Five principles read better as a numbered sequence than as a grid: an odd
   count leaves a grid with a ragged last row, and these are meant to be read
   in order rather than scanned. Each one hangs off a single vertical rule so
   the set reads as one spine of principles.
   ========================================================================== */

.nzp-values {
  position: relative;
  max-width: 820px;
  margin: 0 auto;
  padding: 0;
  list-style: none;
}

/*
 * The spine. Inset at the top and bottom so the rule starts and ends inside
 * the first and last badges rather than floating past them.
 */
.nzp-values::before {
  content: '';
  position: absolute;
  left: 35px;
  top: 44px;
  bottom: 44px;
  width: 2px;
  background: linear-gradient(
    var(--color-secondary-20),
    var(--color-secondary) 12%,
    var(--color-secondary) 88%,
    var(--color-secondary-20)
  );
}

.nzp-value {
  position: relative;
  display: grid;
  grid-template-columns: 72px 1fr;
  gap: var(--space-5);
  align-items: start;
  margin: 0;
  padding: var(--space-5) var(--space-4) var(--space-5) 0;
  border-radius: var(--radius-lg);
  transition: background var(--transition), transform var(--transition);
}
.nzp-value:hover { background: rgba(219, 174, 149, 0.10); transform: translateX(4px); }

/* The badge sits on the spine, so it needs an opaque fill to break the rule. */
.nzp-value__num {
  position: relative;
  z-index: 1;
  width: 72px;
  height: 72px;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  font-family: var(--font-display);
  font-size: var(--fs-lg);
  font-weight: 600;
  color: var(--color-primary);
  background: var(--color-bg);
  border: 2px solid var(--color-secondary);
  transition: background var(--transition), color var(--transition), transform var(--transition);
}
.nzp-value:hover .nzp-value__num {
  background: var(--color-primary);
  border-color: var(--color-primary);
  color: var(--color-secondary);
  transform: scale(1.06);
}

.nzp-value__title {
  font-family: var(--font-display);
  font-size: var(--fs-xl);
  font-weight: 600;
  color: var(--color-primary);
  margin: 0 0 var(--space-2);
  line-height: 1.2;
}
.nzp-value__text {
  margin: 0;
  font-size: var(--fs-md);
  line-height: 1.7;
  color: var(--color-text);
}

/* On phones the badge shrinks and the spine follows it inward. */
@media (max-width: 640px) {
  .nzp-values::before { left: 25px; }
  .nzp-value { grid-template-columns: 52px 1fr; gap: var(--space-4); }
  .nzp-value__num { width: 52px; height: 52px; font-size: var(--fs-base); }
  .nzp-value__title { font-size: var(--fs-lg); }
  .nzp-value__text { font-size: var(--fs-base); }
  .nzp-value:hover { transform: none; }
}


/* --- Mission statement band --------------------------------------------- */

.nzp-mission {
  position: relative;
  overflow: hidden;
  background: var(--color-primary);
  color: var(--color-text-invert);
  padding: var(--space-9) 0;
  text-align: center;
}
/*
 * Same three-layer order as the homepage hero: photograph, then the wash that
 * makes the type readable, then the copy. Declared explicitly rather than
 * left to document order, because a child element otherwise paints above the
 * ::before scrim meant to darken it.
 */
.nzp-mission__bg {
  position: absolute;
  /* Oversized so the drift never exposes an edge, same as the hero band. */
  inset: -5% -7%;
  background-size: cover;
  animation: nzp-drift 42s ease-in-out infinite alternate;
  will-change: transform;
  /* Weighted below centre so the rooflines carry the band rather than the
     bright dusk sky, which reads as a stain in the top corner. */
  background-position: center 68%;
  z-index: 0;
}
.nzp-mission::before {
  content: '';
  position: absolute;
  inset: 0;
  background: linear-gradient(rgba(6, 31, 17, 0.80), rgba(6, 31, 17, 0.90));
  pointer-events: none;
  z-index: 1;
}
.nzp-mission > .nzp-container { position: relative; z-index: 2; }

/* The heading itself, not the statement beneath it, carries the scale here. */
.nzp-mission__eyebrow {
  display: inline-block;
  font-family: var(--font-display);
  font-size: clamp(1.75rem, 3.6vw, 3rem);
  font-weight: 700;
  letter-spacing: -0.01em;
  text-transform: none;
  color: var(--color-secondary);
  margin: 0 0 var(--space-6);
  /* Ruled box so it reads unmistakably as the heading for the band. */
  border: 2px solid var(--color-secondary);
  border-radius: var(--radius-lg);
  padding: var(--space-3) var(--space-6);
}

.nzp-mission__statement {
  font-family: var(--font-display);
  font-size: clamp(1.375rem, 2.6vw, 2.125rem);
  font-weight: 400;
  line-height: 1.45;
  max-width: 900px;
  margin: 0 auto;
  color: #FFFFFF;
  text-wrap: balance;
}
/* The commitment inside the sentence, lifted in brand sand. */
.nzp-mission__statement em { font-style: normal; color: var(--color-secondary); }

.nzp-mission__rule {
  width: 64px;
  height: 2px;
  border: 0;
  background: var(--color-secondary);
  margin: var(--space-6) auto 0;
}

@media (prefers-reduced-motion: reduce) {
  .nzp-mission__bg { animation: none; }
}

/*
 * The mark card holds a map, not a small glyph, so it has to fill the frame.
 * An earlier rule pins `.nzp-kpi__mark svg` to 68x68, which left the Europe
 * map floating in the middle of the card with the sides cut away.
 */
.nzp-kpi__mark { padding: 0; }
.nzp-kpi__mark svg.nzp-kpi__mark-map {
  width: 100%;
  height: 100%;
  max-height: none;
  display: block;
}

/* --- Germany map + legend polish ---------------------------------------- */

/* The star marks offices, not a data band, so it takes a colour of its own. */
/* Light orange, matching the swatch beside "Germany Offices" in the legend. */
.nzp-region-star { fill: #E3925B; stroke: #FFFFFF; stroke-width: 1.6; }
/* Dotted leader tying each star to its name. */
.nzp-region-star__leader {
  stroke: #C2410C;
  stroke-width: 2;
  stroke-dasharray: 2 4;
  stroke-linecap: round;
}
.nzp-region-star__plate {
  fill: rgba(255, 255, 255, 0.94);
  stroke: #E3925B;
  stroke-width: 1.4;
}
.nzp-region-star__label {
  font-family: var(--font-sans);
  font-size: 15px;
  font-weight: 700;
  fill: var(--color-primary);
  stroke: none;
  paint-order: normal;
  dominant-baseline: auto;
}
/*
 * Two stacked silhouettes give the country a solid, extruded edge:
 * `__extrude` sits offset beneath and supplies the depth on the lower-right,
 * `__silhouette` sits square on the border and supplies the crisp outline.
 * Both are under the coloured states, so no line is drawn between states.
 */
/*
 * A stack of offset copies rather than one displaced silhouette: a single
 * offset leaves a visible gap along shallow edges, whereas stacking closes it
 * so the country reads as a solid object with a real side wall.
 */
/* Set on the group: <use> content is a shadow tree, so `.class path` cannot
   reach it, but inheritable properties like fill and stroke do pass through. */
.nzp-map--germany__extrude {
  fill: #46534C;
  stroke: #46534C;
  /*
   * The depth layer carries no heavy stroke of its own: the offset fill is
   * what reads as thickness, and stroking it as well only thickened the mess
   * along the North Sea coast.
   */
  stroke-width: 2;
  stroke-linejoin: round;
}
.nzp-map--germany__silhouette {
  fill: #10231A;
  stroke: #10231A;
  /*
   * 5, not 11. The northern coast carries Halligen islets and fjords only a
   * few units across; an 11-unit stroke on geometry that fine closed over the
   * detail and rendered each islet as a blob, which is what made the top edge
   * look broken. At 5 the outline still reads as heavy but the coastline
   * survives.
   */
  stroke-width: 5;
  stroke-linejoin: round;
  stroke-linecap: round;
}

/* Legend hover lifts every state in that region. */
.nzp-map--germany .nzp-region { transition: filter 160ms ease, stroke 160ms ease; }
.nzp-map--germany .nzp-region.is-active {
  filter: brightness(0.88) saturate(1.25);
  stroke: #061F11;
  stroke-width: 2.4;
}
#nzp-germany-legend li { cursor: pointer; border-radius: var(--radius); transition: background 160ms ease; }
#nzp-germany-legend li.is-active { background: var(--color-bg-alt); }

/* The key sits in its own panel rather than floating on the section. */
.nzp-share .nzp-legend {
  background: var(--color-bg);
  border: 1px solid var(--color-light-dark);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-sm);
  padding: var(--space-5) var(--space-6);
  margin-top: var(--space-5);
}
.nzp-share .nzp-legend li { display: flex; align-items: center; gap: var(--space-3); }
.nzp-share .nzp-legend li + li { margin-top: var(--space-3); }
.nzp-share .nzp-legend__swatch {
  width: 16px; height: 16px;
  border-radius: 3px;
  flex: 0 0 16px;
  box-shadow: inset 0 0 0 1px rgba(6, 31, 17, 0.16);
}
.nzp-share .nzp-legend__value { margin-left: auto; font-weight: 700; color: var(--color-primary); }
.nzp-legend__item--star .nzp-legend__swatch--star { box-shadow: none; }
.nzp-legend__swatch--star svg { fill: #E3925B; }
/* ==========================================================================
   MANAGEMENT TEAM
   Alternating full-width bands rather than a row of equal cards: these
   biographies differ in length by a factor of two, and cards would have
   forced all three down to the shortest.
   ========================================================================== */

/* A quiet line introducing the people, not a banner. Still an h1. */
.nzp-team-lead {
  font-family: var(--font-body);
  font-size: var(--fs-lg);
  font-weight: 700;
  /* Tracking eases off as the size goes up; 0.16em is airy at 22px. */
  letter-spacing: 0.10em;
  text-transform: uppercase;
  color: var(--color-primary);
  margin: 0 0 var(--space-6);
  padding-bottom: var(--space-4);
  border-bottom: 1px solid var(--color-light-dark);
}

/*
 * grid-auto-rows: 1fr makes every row as tall as the tallest, so the three
 * cards match and each portrait can simply fill its own card. Sizing the
 * portrait on its own instead left a gap under the shortest one and cropped
 * the photo in the tallest.
 */
.nzp-team { display: grid; gap: var(--space-7); grid-auto-rows: 1fr; }

.nzp-team-member {
  display: grid;
  grid-template-columns: minmax(0, 360px) minmax(0, 1fr);
  gap: clamp(1.5rem, 4vw, 3.5rem);
  align-items: start;
  background: #FFFFFF;
  /*
   * Deliberately darker than --color-light-dark: these cards sit on the pale
   * alt background, where a near-white hairline is invisible and the card
   * reads as floating rather than framed.
   */
  border: 1px solid rgba(6, 31, 17, 0.16);
  border-radius: var(--radius);
  overflow: hidden;
  box-shadow: 0 2px 22px rgba(6, 31, 17, 0.06);
  transition: border-color var(--transition), box-shadow var(--transition),
              transform var(--transition);
}
/*
 * One restrained hover: the card lifts, the border picks up the brand sand
 * and the portrait pushes in very slightly. Enough to make the row feel
 * alive under the pointer without adding anything to look at when still.
 */
.nzp-team-member:hover,
.nzp-team-member:focus-within {
  border-color: var(--color-secondary);
  box-shadow: 0 12px 34px rgba(6, 31, 17, 0.14);
  transform: translateY(-4px);
}
.nzp-team-member:hover .nzp-team-member__portrait img { transform: scale(1.045); }
.nzp-team-member:hover .nzp-team-member__rule { width: 92px; }
/* Every other person mirrors, so the eye zig-zags down the page. */
.nzp-team-member:nth-child(even) { grid-template-columns: minmax(0, 1fr) minmax(0, 360px); }
.nzp-team-member:nth-child(even) .nzp-team-member__portrait { order: 2; }

/*
 * A fixed portrait height rather than one stretched to whatever the biography
 * beside it happens to run to. Left to stretch, the shortest bio gave the
 * shortest frame, and object-fit: cover then took the difference off the
 * bottom of that person's photograph - so one face sat cropped at the chest
 * while the others did not. Fixing the height makes the three identical and
 * the crop predictable; the text column absorbs the variation instead.
 */
.nzp-team-member__portrait {
  position: relative;
  align-self: stretch;
  height: auto;
  min-height: 460px;
  background: var(--color-light-dark);
}
.nzp-team-member__portrait img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  /* Portraits are framed head-and-shoulders, so hold the top of the frame. */
  object-position: center top;
  transition: transform 600ms cubic-bezier(0.22, 0.61, 0.36, 1);
}

/* Stand-in for a person whose photograph has not been supplied. */
.nzp-team-member__placeholder {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: var(--space-3);
  background: linear-gradient(160deg, #0C2A18 0%, #061F11 100%);
  color: #FFFFFF;
}
.nzp-team-member__initials {
  font-family: var(--font-display);
  font-size: clamp(3rem, 7vw, 4.5rem);
  font-weight: 700;
  letter-spacing: 0.06em;
  line-height: 1;
  color: var(--color-secondary);
}
.nzp-team-member__pending {
  font-size: var(--fs-xs);
  letter-spacing: 0.10em;
  text-transform: uppercase;
  color: rgba(255, 255, 255, 0.62);
}

/* Matches the portrait so a short biography still fills the card. */
.nzp-team-member { min-height: 460px; }
.nzp-team-member__body { padding: clamp(1.75rem, 3vw, 2.75rem) clamp(1.5rem, 3vw, 2.75rem); }
.nzp-team-member__name { margin: 0 0 var(--space-1); letter-spacing: -0.02em; }
.nzp-team-member__role {
  display: block;
  font-size: var(--fs-sm);
  font-weight: 700;
  letter-spacing: 0.10em;
  text-transform: uppercase;
  color: var(--color-secondary);
}
.nzp-team-member__rule {
  width: 56px;
  height: 3px;
  margin: var(--space-4) 0 var(--space-5);
  border: 0;
  background: var(--color-secondary);
  transition: width var(--transition);
}
.nzp-team-member__body p { margin-bottom: var(--space-4); }
.nzp-team-member__body p:last-child { margin-bottom: 0; }

@media (max-width: 860px) {
  /* Stacked, and the mirrored row un-mirrors so the portrait always leads. */
  .nzp-team-member,
  .nzp-team-member:nth-child(even) { grid-template-columns: 1fr; gap: 0; }
  .nzp-team { grid-auto-rows: auto; }
  .nzp-team-member:nth-child(even) .nzp-team-member__portrait { order: 0; }
  .nzp-team-member,
  .nzp-team-member__portrait { min-height: 0; }
  .nzp-team-member__portrait { height: 360px; }
}


/* ==========================================================================
   CASE STUDY HEADING
   Sits directly above the before/after pair on the Strategy page.
   ========================================================================== */

.nzp-case-head { margin-bottom: var(--space-5); }
.nzp-case-head h3 { margin-bottom: var(--space-1); letter-spacing: -0.01em; }
/*
 * Deliberately NOT uppercased, unlike the other eyebrows on the site: German
 * has no uppercase eszett in common use, so text-transform turns "Straße"
 * into "STRASSE" and the street name stops matching the sign on the wall.
 */
.nzp-case-head p {
  margin: 0;
  font-size: var(--fs-base);
  font-weight: 600;
  color: var(--color-text-muted);
}


/* ==========================================================================
   CAROUSEL ARROWS
   Shared by the Key Facts strip and the SDG rail. The first click hands the
   strip from the CSS marquee over to manual paging (js/carousel.js), so the
   arrows are the way to stop the movement as well as the way to steer it.
   ========================================================================== */

/*
 * The shell is what positions the arrows; the strip inside it is masked so
 * the cards fade out towards both edges. The two cannot be the same element:
 * a mask applies to descendants, so arrows placed inside the strip would fade
 * away with the cards they sit on.
 */
.nzp-carousel-shell { position: relative; }

/*
 * No edge mask. The fade was there so the arrows sat on clean ground, but it
 * read as a white blur smeared over the first and last card - the client's
 * words - so the strip now runs to a hard edge and the arrows rely on their
 * own solid disc and shadow to stay legible over a card.
 */
.nzp-carousel-arrow {
  position: absolute;
  top: 50%;
  transform: translateY(-50%);
  z-index: 3;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 48px;
  height: 48px;
  padding: 0;
  border: 1px solid rgba(6, 31, 17, 0.14);
  border-radius: 50%;
  background: rgba(255, 255, 255, 0.92);
  box-shadow: 0 3px 14px rgba(6, 31, 17, 0.16);
  color: var(--color-primary);
  cursor: pointer;
  transition: background var(--transition), color var(--transition),
              box-shadow var(--transition), transform var(--transition);
}
/* Sits inside the fully transparent band the mask above reserves for it. */
.nzp-carousel-arrow--prev { left: 14px; }
.nzp-carousel-arrow--next { right: 14px; }
@media (max-width: 640px) {
  .nzp-carousel-arrow--prev { left: 6px; }
  .nzp-carousel-arrow--next { right: 6px; }
}

.nzp-carousel-arrow svg {
  width: 22px;
  height: 22px;
  fill: none;
  stroke: currentColor;
  stroke-width: 2.4;
  stroke-linecap: round;
  stroke-linejoin: round;
}
.nzp-carousel-arrow:hover,
.nzp-carousel-arrow:focus-visible {
  background: var(--color-primary);
  border-color: var(--color-primary);
  color: #FFFFFF;
  box-shadow: 0 5px 20px rgba(6, 31, 17, 0.28);
}
.nzp-carousel-arrow:active { transform: translateY(-50%) scale(0.94); }

@media (max-width: 640px) {
  .nzp-carousel-arrow { width: 40px; height: 40px; }
  .nzp-carousel-arrow svg { width: 18px; height: 18px; }
}

/* --- Two-phase: heading centred over the illustration --------------------- */
/*
 * The section heading centres on the container while the house centres on the
 * middle grid column. Those are only the same point if the outer columns are
 * equal, and they are not - the track is 1fr / 1.1fr / 1fr. Making the outer
 * columns match puts the middle column, and so the house, on the container's
 * centre line, which is where the heading already sits.
 */
.nzp-phases { grid-template-columns: minmax(0, 1fr) minmax(280px, 1fr) minmax(0, 1fr); }

/* --- ESG section: photographic backdrop ---------------------------------- */
/*
 * The image is set on the section from the template, so it can be swapped in
 * the Customizer or replaced on disk without touching this file. A soft white
 * veil sits over it to hold contrast for the copy above and below the diagram.
 */
/*
 * Two stacked photographs cannot be dissolved by masking one of them: the
 * header above is position:relative and keeps painting over the transparent
 * region, so the picture still begins on a hard line at its edge.
 *
 * Both sides are instead faded to the SAME colour, so they meet on a shared
 * tone and the join disappears - brand green at the top, where the video band
 * sits, and the pale section colour at the bottom, where the SDG band starts.
 * No overlap and no stacking order to get wrong.
 */
.nzp-esg-section {
  position: relative;
  background-size: cover;
  background-position: center;
  background-repeat: no-repeat;
  padding-top: var(--space-9);
  padding-bottom: var(--space-9);
}
.nzp-esg-section::before {
  content: '';
  position: absolute;
  inset: 0;
  pointer-events: none;
  background:
    linear-gradient(to bottom, var(--color-primary) 0, rgba(6, 31, 17, 0) 190px),
    linear-gradient(to top, var(--color-bg-alt) 0, rgba(243, 243, 243, 0) 150px);
}

/* The video band fades to the same green, so both sides meet on one tone. */
.nzp-page-header--video::after {
  content: '';
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  height: 130px;
  pointer-events: none;
  z-index: 2;
  background: linear-gradient(to bottom, rgba(6, 31, 17, 0) 0, var(--color-primary) 100%);
}
/*
 * The photograph meets the dark video header above and the pale SDG band below.
 * Butted together those edges read as two images stuck end to end, so each is
 * dissolved into its neighbour with a gradient in the section's own colours.
 * No flat veil over the middle - the picture still reads as itself.
 */

.nzp-esg-section > .nzp-container { position: relative; z-index: 1; }

/* --- Investors: public reports, then the login reveal --------------------- */
.nzp-article-grid--2 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
@media (max-width: 760px) { .nzp-article-grid--2 { grid-template-columns: 1fr; } }

/* --- Key Facts carousel --------------------------------------------------- */
/*
 * A continuous marquee, matching the photo strip and the SDG rail elsewhere on
 * the site. The track holds two identical passes and travels exactly -50%, so
 * the second copy lands where the first began and the loop is seamless.
 *
 * Card width is viewport-relative with no upper cap: a fixed maximum is what
 * put six SDG cards in frame on a wide monitor, and the same would happen
 * here.
 */
.nzp-kpi-carousel {
  position: relative;
  overflow: hidden;
  /*
   * Full-bleed: the track sits outside .nzp-container so it runs to both
   * window edges. Capped inside the container it stopped short of the screen
   * on either side, which read as a mistake rather than as a crop.
   */
  width: 100%;
}

.nzp-kpi-carousel__track {
  display: flex;
  gap: var(--space-5);
  width: max-content;
  animation: nzp-kpi-scroll 46s linear infinite;
}
.nzp-kpi-carousel:hover .nzp-kpi-carousel__track,
.nzp-kpi-carousel:focus-within .nzp-kpi-carousel__track {
  animation-play-state: paused;
}

.nzp-kpi-carousel__track > .nzp-kpi {
  flex: 0 0 max(280px, 27vw);
}

@keyframes nzp-kpi-scroll {
  from { transform: translateX(0); }
  to   { transform: translateX(-50%); }
}

@media (max-width: 640px) {
  .nzp-kpi-carousel__track > .nzp-kpi { flex: 0 0 78vw; }
  .nzp-kpi-carousel__track { animation-duration: 34s; }
}

/* Standing still is the accessible default when motion is unwelcome. */
@media (prefers-reduced-motion: reduce) {
  .nzp-kpi-carousel__track { animation: none; }
  /* Not a native scroller. js/carousel.js drives this strip by transform and
     handles the drag itself; leaving the browser scrolling it too meant two
     mechanisms moving the same track against each other. */
  .nzp-kpi-carousel { overflow-x: hidden; }
}

/* --- Sticky footer ------------------------------------------------------- */
/*
 * On a page shorter than the window - Contact especially - the footer stopped
 * wherever the content ended and the page background showed beneath it as a
 * white band. Making the body a column and letting the main region absorb the
 * slack pushes the footer to the bottom without stretching anything else.
 */
body { display: flex; flex-direction: column; min-height: 100vh; }
/* A column, so a single-section page can grow that section to fill the slack
   rather than leaving it pooled beneath the content. */
.nzp-site-content { flex: 1 0 auto; display: flex; flex-direction: column; }
.nzp-footer { flex-shrink: 0; }

/* --- Overview: copy sits square against the slideshow --------------------- */
/*
 * The column was running ragged on its right edge because the text block had
 * no measure of its own and the paragraphs were not sharing a baseline with
 * the panel beside them.
 */
.nzp-text-media__text { align-self: start; }
.nzp-text-media__text > *:first-child { margin-top: 0; }
.nzp-text-media__text > *:last-child { margin-bottom: 0; }
/*
 * The paragraphs are direct descendants of .nzp-text-media - there is no
 * __text wrapper on this page, which is why the previous rule matched nothing
 * and the copy stayed ragged twice over.
 */
/*
 * Justified, but not hyphenated. hyphens:auto was breaking words across lines
 * to make the justification fit, which is what produced all the half-words.
 * Without it the browser has to solve the line by spacing alone, so the column
 * is widened below to give it enough room to do that without opening rivers.
 */
/*
 * Desktop only, and that min-width matters. These rules used to sit bare at
 * the end of the stylesheet, so they re-declared the two-column grid AFTER
 * the mobile media query had stacked it - same specificity, later in source,
 * so the desktop layout won on phones too. The copy column ended up a sliver
 * of justified text with the photo strip hanging off the right edge.
 */
@media (min-width: 769px) {
  .nzp-text-media p {
    text-align: justify;
    text-justify: inter-word;
    hyphens: manual;
  }

  /*
   * More room for the copy, and the two columns stretch to a common height so
   * the strip starts and finishes level with the text rather than floating
   * centred against it.
   */
  .nzp-text-media {
    grid-template-columns: minmax(0, 1.45fr) minmax(0, 1fr);
    align-items: stretch;
  }

  /*
   * Sized explicitly rather than stretched. Both height:100% and
   * min-height:100% resolve against a grid row whose own height is auto, so
   * the panel kept collapsing back to the images' natural size. A fixed
   * height is deterministic and lands level with the copy beside it.
   */
  .nzp-text-media > .nzp-slideshow--panel .nzp-slideshow__track { align-items: stretch; }
  .nzp-text-media > .nzp-slideshow--panel .nzp-slideshow__item {
    aspect-ratio: auto;
    height: 340px;
  }
}

@media (max-width: 768px) {
  .nzp-text-media { grid-template-columns: 1fr; gap: var(--space-6); }
  /* Copy first, photography beneath it. */
  .nzp-text-media > *:first-child { order: 1; }
  .nzp-text-media > * { order: 2; }
}

/* --- Track Record: chart panel ------------------------------------------- */
.nzp-chart-panel {
  position: relative;
  background: var(--color-bg-alt);
  border: 1px solid var(--color-light-dark);
  border-radius: var(--radius-lg);
  padding: var(--space-7) var(--space-6) var(--space-6);
}
/*
 * Positioned against the inner plot area rather than the panel, so it sits in
 * the top right of the white chart itself instead of straddling the join
 * between the white and the grey.
 */
.nzp-chart { position: relative; }
.nzp-chart-panel__mark {
  position: absolute;
  top: var(--space-4);
  right: var(--space-4);
  width: 44px;
  height: auto;
  opacity: 0.5;
  pointer-events: none;
}

/* --- Track Record: portfolio today, read as a vertical list --------------- */
.nzp-today { list-style: none; margin: 0 auto; padding: 0; max-width: 940px; }
.nzp-today__row {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 300px;
  gap: var(--space-7);
  align-items: center;
  padding: var(--space-6) 0;
  margin: 0;
  border-bottom: 1px solid var(--color-light-dark);
}
.nzp-today__row:last-child { border-bottom: 0; }

.nzp-today__value {
  display: block;
  font-family: var(--font-display);
  font-size: clamp(2.4rem, 5vw, 3.6rem);
  font-weight: 400;
  line-height: 1.05;
  color: var(--color-primary);
}
.nzp-today__label {
  display: block;
  margin-top: var(--space-3);
  font-size: var(--fs-md);
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--color-text-muted);
}
.nzp-today__media {
  aspect-ratio: 16 / 10;
  overflow: hidden;
  border-radius: var(--radius-lg);
  background: var(--color-light-dark);
  box-shadow: var(--shadow-sm);
}
.nzp-today__media img { width: 100%; height: 100%; object-fit: cover; }
/* The map card brings its own framing, which the row supplies instead. */
.nzp-today__media .nzp-kpi__map-wrap--tilted { background: var(--color-bg-alt); }

@media (max-width: 780px) {
  .nzp-today__row { grid-template-columns: 1fr; gap: var(--space-5); }
  .nzp-today__media { order: -1; }
}

/*
 * The press cards once carried a 22% dark-green scrim. That was there because
 * all three cards showed the same photograph of one building, and the tint
 * made the repetition read as a deliberate set rather than a mistake.
 *
 * The cards now carry the brand collage, which reads as deliberate on its own,
 * and the scrim was costing 29 luma - the cards measured 126 against the 155
 * of the investor cards running the same artwork untinted, which is why they
 * looked dark next to each other. Removed, so the two match.
 */
.nzp-press-card__media { position: relative; }

/* --- Key Facts: the portfolio-area map, tilted ---------------------------- */
.nzp-kpi__map-wrap--tilted {
  width: 100%;
  height: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
  /* Perspective on the wrapper, rotation on the map, so the tilt reads as
     depth rather than as a squashed image. */
  perspective: 700px;
  overflow: hidden;
}
.nzp-kpi__map-wrap--tilted .nzp-kpi__map {
  background: none;
  padding: 0;
  /*
   * A steeper tilt now that the map has real thickness to show. The side wall
   * is built in the SVG itself, so the rotation exposes it rather than just
   * squashing a flat silhouette.
   */
  transform: rotateX(52deg) rotateZ(-6deg) scale(1.7);
  transform-origin: 50% 56%;
  /* A tight contact shadow rather than a wide blur, which was reading as a
     smudge under a flat shape instead of as an object sitting on a surface. */
  filter: drop-shadow(0 5px 5px rgba(6, 31, 17, 0.32));
}
.nzp-kpi__map-wall path { fill: #6E7C75; stroke: #6E7C75; stroke-width: 2; }
.nzp-kpi__map-wrap--tilted .nzp-kpi__map svg {
  max-height: none;
  height: 205px;
  width: auto;
}

/* --- Contact: no dead space between the form and the footer -------------- */
.nzp-contact-layout { padding-bottom: 0; }
body.page-template-page-contact .nzp-section:last-of-type,
.nzp-contact-layout ~ * { margin-bottom: 0; }
/*
 * With the footer pinned, a short form left a large void above it. The layout
 * now centres in whatever height is going and the message field grows to take
 * up the slack, so the page reads as composed rather than as content that ran
 * out.
 */
.nzp-contact-section {
  padding-bottom: var(--space-8);
  display: flex;
  align-items: center;
  /* Absorbs whatever height is left between header and footer. */
  flex: 1 0 auto;
}
.nzp-contact-section > .nzp-container { width: 100%; }
.nzp-contact-grid textarea,
.nzp-contact-grid .wpcf7 textarea { min-height: 220px; }

/* --- Manage-to-Green: framed video --------------------------------------- */
.nzp-video-frame {
  /* White on white was invisible; the frame now carries the brand green with
     a sand keyline so it reads as a deliberate mount. */
  border: 2px solid var(--color-primary);
  border-radius: var(--radius-lg);
  padding: var(--space-3);
  background: var(--color-primary);
  box-shadow: 0 10px 30px rgba(6, 31, 17, 0.22);
  outline: 1px solid var(--color-secondary);
  outline-offset: 4px;
  max-width: 900px;
  margin: 0 auto var(--space-4);
}
.nzp-video-frame video {
  display: block;
  width: 100%;
  height: auto;
  border-radius: var(--radius);
}

/* --- ESG: diagram right, open pillar's text on the left ------------------ */
/*
 * Flex, not grid. As a grid the three panels shared a column with the diagram
 * and, while hidden, still occupied their grid area: in the collapsed (zero
 * width) column their text wrapped one word per line and inflated the row to
 * roughly 900px, which pushed the circles out of view. Absolutely positioning
 * them takes them out of flow entirely, so the diagram's box is its own.
 */
.nzp-venn {
  position: relative;
  display: flex;
  /* Centred until a pillar is chosen; the diagram then eases to the right. */
  justify-content: center;
  align-items: center;
  max-width: 1120px;
  min-height: 480px;
  margin: 0 auto;
  /* An earlier rule pins aspect-ratio 1/0.92 for the old square layout. At
     this width that forced a ~1030px tall box, leaving a large empty gap
     above the circles. The box sizes from its contents now. */
  aspect-ratio: auto;
}
/*
 * The diagram is translated rather than re-justified: justify-content is not
 * an animatable property, so switching it made the circles jump. Translating
 * keeps the same end position but eases into it.
 */
.nzp-venn:has(.nzp-venn-panel.is-open) .nzp-venn__svg { transform: translateX(clamp(0px, 26vw, 292px)); }

.nzp-venn__svg {
  width: 100%;
  max-width: 620px;
  height: auto;
  flex: 0 0 auto;
  transition: transform 420ms cubic-bezier(0.4, 0, 0.2, 1);
  /*
   * Frosted glass rather than a tinted card. At 86% the panel was effectively
   * opaque and read as a white rectangle pasted over the photograph; at 22%
   * with a heavy blur the planting stays visible through it while the blur
   * flattens the detail enough for the linework to hold. The hairline and the
   * inset highlight are what give the pane an edge without a hard border.
   */
  border: 1px solid rgba(255, 255, 255, 0.45);
  border-radius: 22px;
  padding: var(--space-6);
  background: rgba(255, 255, 255, 0.22);
  backdrop-filter: blur(22px) saturate(1.15);
  -webkit-backdrop-filter: blur(22px) saturate(1.15);
  box-shadow:
    0 24px 60px rgba(6, 31, 17, 0.28),
    inset 0 1px 0 rgba(255, 255, 255, 0.55);
  box-sizing: border-box;
}

.nzp-venn-panel {
  position: absolute;
  /*
   * `inset: auto 0 0` from the earlier layout pinned this to the bottom of the
   * container. Combined with top:50% it produced a squeezed box whose text
   * spilled out of the bottom, so every edge is reset explicitly here.
   */
  inset: auto auto auto 0;
  top: 50%;
  right: auto;
  bottom: auto;
  height: auto;
  max-height: none;
  transform: translate(-10px, -50%);
  width: calc(100% - 560px);
  min-width: 300px;
  opacity: 0;
  visibility: hidden;
  transition: opacity 220ms ease, transform 220ms ease, visibility 220ms;
  /*
   * Same frosted glass as the diagram panel, so the pair read as one object.
   * Slightly denser than the square because this one carries body copy and
   * has to stay comfortable to read over a photograph.
   */
  background: rgba(255, 255, 255, 0.34);
  backdrop-filter: blur(22px) saturate(1.15);
  -webkit-backdrop-filter: blur(22px) saturate(1.15);
  border: 1px solid rgba(255, 255, 255, 0.45);
  border-left: 3px solid currentColor;
  border-radius: 0 22px 22px 0;
  box-shadow:
    0 24px 60px rgba(6, 31, 17, 0.28),
    inset 0 1px 0 rgba(255, 255, 255, 0.55);
  padding: var(--space-6);
}
.nzp-venn-panel.is-open { opacity: 1; visibility: visible; transform: translate(0, -50%); }

/* Dotted lead from the panel across to the circle it belongs to. */
.nzp-venn-panel::after {
  content: '';
  position: absolute;
  top: 50%;
  left: 100%;
  width: var(--space-6);
  border-top: 2px dotted currentColor;
  opacity: 0.65;
}

/* The pillar's colour carries through to its bullet ticks. */
.nzp-venn-panel .nzp-list--check li::before { color: currentColor; }
/*
 * No outline. An added stroke on coloured type thickens the letterforms and
 * reads as an effect; a short shadow underneath gives the same separation
 * from the glass while leaving the shapes alone.
 */
.nzp-venn-panel h3 {
  color: currentColor;
  paint-order: normal;
  -webkit-text-stroke: 0;
  text-shadow: 0 1px 2px rgba(6, 31, 17, 0.38);
  /*
   * Governance is a light teal and Social a light amber; at full strength on a
   * pale frosted panel neither has the contrast to be read, and a shadow
   * cannot supply contrast the colour itself lacks. Darkening each heading
   * against its own hue keeps the pillar identifiable while making it legible.
   */
  filter: brightness(0.62) saturate(1.35);
}

@media (max-width: 900px) {
  .nzp-venn { display: block; min-height: 0; }
  .nzp-venn__svg { max-width: 520px; margin: 0 auto; display: block; }
  .nzp-venn-panel {
    position: static;
    transform: none;
    width: auto;
    margin-top: var(--space-5);
  }
  .nzp-venn-panel.is-open { transform: none; }
  .nzp-venn-panel:not(.is-open) { display: none; }
  .nzp-venn-panel::after { display: none; }
}

/* --- Share of area: title centred over the chart and its key ------------- */
.nzp-share { text-align: center; }
.nzp-share__title {
  margin: 0 auto var(--space-5);
  font-family: var(--font-display);
  font-size: var(--fs-lg);
  font-weight: 600;
  color: var(--color-primary);
}
.nzp-share .nzp-legend { display: inline-block; text-align: left; }

.nzp-legend__swatch--star {
  background: none !important;
  display: inline-flex;
  align-items: center;
  justify-content: center;
}
.nzp-legend__swatch--star svg { width: 100%; height: 100%; fill: var(--color-secondary); }

/* --- Office map: raised countries ---------------------------------------- */
/*
 * Three stacked copies per country. The shadow and the wall sit beneath the
 * face and are offset down-right, so only the sliver of each that protrudes
 * past the face is visible - which reads as thickness lit from the upper left.
 */
.nzp-country-raised__shadow {
  fill: rgba(0, 0, 0, 0.45);
  filter: blur(3px);
}
.nzp-country-raised__wall {
  fill: rgba(6, 31, 17, 0.85);
}
/*
 * No fill of its own beyond a fractionally brighter tone than the flat
 * countries, so the emphasis comes from the lift and the heavy white edge
 * rather than from colour.
 */
/*
 * A hairline only. The lift and the cast shadow carry the emphasis; a heavy
 * white rim read as an outline drawn on top of the map rather than as a raised
 * surface, and thickened the coastline into something clumsy.
 */
.nzp-country-raised__face {
  fill: rgba(255, 255, 255, 0.22);
  stroke: rgba(255, 255, 255, 0.75);
  stroke-width: 1.2;
  stroke-linejoin: round;
  paint-order: stroke fill;
}
/*
 * Luxembourg is only about ten units across at this zoom and its own marker
 * covers most of it, so it keeps a slightly firmer edge - enough to be found,
 * not enough to look drawn on.
 */
.nzp-country-raised[data-country="luxembourg"] .nzp-country-raised__face {
  stroke-width: 2.6;
}
.nzp-country-raised {
  transition: transform 220ms ease;
}
/* Lifting a little further on hover reinforces that they are raised objects. */
.nzp-country-raised.is-active { transform: translate(-2px, -3px); }

/* --- Office map: labels are HTML, so they always fit their text ---------- */
.nzp-map--office {
  position: relative;
  /*
   * A map has to end somewhere, and without a frame that edge reads as an
   * accidental crop. The border plus rounded corners state the boundary
   * deliberately, so it looks like a map panel rather than a truncated image.
   */
  border: 1px solid rgba(255, 255, 255, 0.24);
  border-radius: var(--radius-lg);
  box-shadow: 0 14px 36px rgba(0, 0, 0, 0.28);
  overflow: hidden;
  max-width: 100%;
}
/* A faint inward vignette so the landmass fades into the frame at the edges. */
.nzp-map--office::after {
  content: '';
  position: absolute;
  inset: 0;
  pointer-events: none;
  border-radius: inherit;
  box-shadow: inset 0 0 44px 10px rgba(6, 31, 17, 0.55);
}
/* Hover and keyboard focus lift both the pin and its label together. */
.nzp-pin { cursor: pointer; }
.nzp-pin .nzp-pin__dot { transition: r 160ms ease, fill 160ms ease; }
/*
 * Red, not brand sand: sand is the fill used for Germany, so an active pin
 * sitting on Germany disappeared into it.
 */
/* The dot alone turns red; the label keeps its black-on-white treatment. */
.nzp-pin.is-active .nzp-pin__dot { r: 9; fill: #D93025; }
.nzp-pin.is-active .nzp-pin__pulse { fill: #D93025 !important; }
/*
 * Hidden until the matching entry in the list below the map is hovered, so the
 * map itself stays uncluttered. Black on white with a sand outline - the pin
 * turns red on hover, the label deliberately does not.
 */
.nzp-pin-label {
  position: absolute;
  z-index: 2;
  transform: translateY(-50%);
  white-space: nowrap;
  font-family: var(--font-sans);
  font-size: 14px;
  font-weight: 700;
  line-height: 1;
  color: #1A2620;
  background: #FFFFFF;
  border: 2px solid var(--color-secondary);
  border-radius: 999px;
  padding: 6px 12px;
  pointer-events: none;
  opacity: 0;
  visibility: hidden;
  transition: opacity 180ms ease, visibility 180ms;
}
.nzp-pin-label.is-active { opacity: 1; visibility: visible; }
/* Sit clear of the dot on whichever side the office was assigned. */
.nzp-pin-label.is-right { margin-left: 16px; }
.nzp-pin-label.is-left  { transform: translate(-100%, -50%); margin-left: -16px; }
/*
 * The office list drives the reveal, so it reads as interactive. The active
 * item already takes a sand background further up the sheet; setting sand text
 * here as well left the name invisible against its own highlight, so it keeps
 * the dark ink and simply sits on top.
 */
.nzp-office-list li { cursor: pointer; transition: background 160ms ease, color 160ms ease; }
.nzp-office-list li.is-active { color: var(--color-primary); }

@media (max-width: 700px) {
  .nzp-pin-label { font-size: 12px; padding: 4px 9px; }
}

/* --- Office map: label plates -------------------------------------------- */
.nzp-pin__plate {
  fill: rgba(6, 31, 17, 0.82);
  stroke: rgba(219, 174, 149, 0.55);
  stroke-width: 1;
}
/* The plate supplies the contrast now, so the label drops its dark outline.
   Left in place it painted over the white fill and read as dark grey. */
.nzp-pin__label { stroke: none; fill: #FFFFFF; }

/* --- Value icons --------------------------------------------------------- */
.nzp-value__icon {
  width: 1.05em;
  height: 1.05em;
  flex: 0 0 auto;
  color: var(--color-secondary);
  transition: color var(--transition), transform var(--transition);
}
.nzp-value__title {
  display: flex;
  align-items: center;
  gap: var(--space-3);
}
.nzp-value:hover .nzp-value__icon { color: var(--color-primary); transform: scale(1.08); }

@media (max-width: 768px) {
  .nzp-mission { padding: var(--space-8) 0; }
}


/* ==========================================================================
   INVESTORS PAGE HEAD
   Heading left, credit contact right, as one row across the top. The heading
   column is deliberately narrow so the title wraps over several lines rather
   than running the full width and leaving the contact stranded below it.
   ========================================================================== */

.nzp-investors-head {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 342px);
  gap: clamp(1.5rem, 4vw, 3.5rem);
  /*
   * Stretch, not start: the two columns are different natural heights, so
   * aligning only their tops left the heading finishing well above the
   * bottom of the contact card. Both now fill the row, and the rule under
   * the heading is pushed to the foot of its column, so the block reads as
   * square with the card on both edges.
   */
  align-items: stretch;
  margin-bottom: var(--space-8);
}
/*
 * A sand bar down the leading edge rather than a short rule floating under
 * the words. It mirrors the contact card opposite, which carries the same
 * 4px edge, so the two halves of the row read as a matched pair instead of
 * a heading and an unrelated panel.
 */
.nzp-investors-head__intro {
  display: flex;
  flex-direction: column;
  justify-content: center;
  border-left: 4px solid var(--color-secondary);
  padding-left: clamp(1rem, 2vw, 1.75rem);
}
.nzp-investors-head__eyebrow {
  font-size: var(--fs-xs);
  font-weight: 700;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--color-text-muted);
  margin: 0 0 var(--space-3);
}
.nzp-investors-head__intro h2 { max-width: 16ch; margin-bottom: 0; }

@media (max-width: 860px) {
  .nzp-investors-head { grid-template-columns: 1fr; }
  .nzp-investors-head__intro h2 { max-width: none; }
}


/* ==========================================================================
   CREDIT-RELATED CONTACT
   A compact panel sitting in the right-hand column of the row above.
   ========================================================================== */

.nzp-credit-contact {
  padding: var(--space-5);
  background: #EFF2F0;                       /* soft green-grey, not flat white */
  border: 1px solid rgba(6, 31, 17, 0.14);
  border-radius: var(--radius);
  /* Brand sand down the leading edge, the one bit of colour in the block. */
  border-left: 4px solid var(--color-secondary);
}

.nzp-credit-contact__title {
  font-family: var(--font-body);
  font-size: var(--fs-xs);
  font-weight: 700;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--color-text-muted);
  margin: 0 0 var(--space-3);
  padding-bottom: var(--space-3);
  border-bottom: 1px solid rgba(6, 31, 17, 0.12);
}

.nzp-credit-contact__person {
  display: flex;
  align-items: center;
  gap: var(--space-4);
}

/* Small and fixed. The portrait supports the details, it is not the subject. */
.nzp-credit-contact__portrait {
  flex: 0 0 74px;
  width: 74px;
  height: 94px;
  border-radius: calc(var(--radius) - 2px);
  overflow: hidden;
  border: 1px solid rgba(6, 31, 17, 0.16);
  box-shadow: 0 3px 12px rgba(6, 31, 17, 0.10);
  background: var(--color-light-dark);
}
.nzp-credit-contact__portrait img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center top;
  display: block;
}

.nzp-credit-contact__name {
  font-family: var(--font-display);
  font-size: var(--fs-md);
  line-height: 1.15;
  margin: 0 0 4px;
}
.nzp-credit-contact__role {
  /* Tracked tighter than the other eyebrows on the site so the job title
     holds one line in this narrow card. */
  font-size: 0.68rem;
  font-weight: 700;
  letter-spacing: 0.04em;
  white-space: nowrap;
  text-transform: uppercase;
  color: var(--color-secondary);
  margin: 0 0 var(--space-3);
}

.nzp-credit-contact__email {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 5px var(--space-3);
  background: #FFFFFF;
  border: 1px solid rgba(6, 31, 17, 0.16);
  border-radius: 999px;
  color: var(--color-primary);
  font-size: var(--fs-xs);
  font-weight: 600;
  text-decoration: none;
  transition: background var(--transition), color var(--transition),
              border-color var(--transition);
}
.nzp-credit-contact__email:hover,
.nzp-credit-contact__email:focus-visible {
  background: var(--color-primary);
  border-color: var(--color-primary);
  color: #FFFFFF;
}
.nzp-credit-contact__icon { display: inline-flex; }
.nzp-credit-contact__icon svg { width: 14px; height: 14px; }

@media (max-width: 420px) {
  .nzp-credit-contact__person { flex-direction: column; align-items: flex-start; }
}


/* ==========================================================================
   INVESTOR DOCUMENT SLIDER
   A real horizontal scroller with snap points, not a grid and not a marquee.
   A grid leaves a ragged hole whenever the number of documents is not a
   multiple of the column count, and there is no reason that number should
   ever be even. The track simply grows as documents are added.
   ========================================================================== */

.nzp-doc-shell { position: relative; }

.nzp-doc-slider {
  overflow-x: auto;
  overflow-y: hidden;
  scroll-snap-type: x mandatory;
  scroll-padding-left: 2px;
  /* Room for the lift-on-hover and its shadow, which a clipped box would cut. */
  padding: 4px 4px 14px;
  margin: -4px -4px -14px;
  scrollbar-width: thin;
}
/*
 * A normal-width flex row, NOT max-content. With max-content the track sizes
 * itself to its contents while the cards size themselves to the track, and
 * adding flex-grow makes that circular - the cards blow up to several times
 * their intended width. At width:100% the free space is a real number the
 * cards can share, and because they never shrink, enough of them simply
 * overflow and the parent scrolls.
 */
.nzp-doc-track {
  display: flex;
  gap: var(--space-5);
  width: 100%;
}

.nzp-doc {
  /*
   * vw, not %: a percentage flex-basis resolves against the whole max-content
   * track, not the visible window, which is the trap that once produced one
   * enormous slide on the Key Facts strip.
   *
   * grow:1 so that when the documents already fit they spread to the full
   * width and their right edge lands under the contact card above. Add enough
   * of them and the basis exceeds the row, leaving no free space to grow into,
   * so the strip goes back to scrolling at its natural card width.
   */
  flex: 1 0 clamp(240px, 26vw, 330px);
  scroll-snap-align: start;
  display: flex;
}
.nzp-doc__link {
  display: flex;
  flex-direction: column;
  width: 100%;
  overflow: hidden;
  background: #FFFFFF;
  border: 1px solid rgba(6, 31, 17, 0.14);
  border-radius: var(--radius);
  text-decoration: none;
  color: inherit;
  transition: border-color var(--transition), box-shadow var(--transition),
              transform var(--transition);
}
.nzp-doc__link:hover,
.nzp-doc__link:focus-visible {
  border-color: var(--color-secondary);
  box-shadow: 0 12px 30px rgba(6, 31, 17, 0.13);
  transform: translateY(-4px);
}

/* Photography leads the card, matching the press cards on the Press page. */
.nzp-doc__media {
  display: block;
  aspect-ratio: 16 / 9;
  overflow: hidden;
  background: var(--color-light-dark);
}
.nzp-doc__media img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
  transition: transform 500ms ease;
}
.nzp-doc__link:hover .nzp-doc__media img,
.nzp-doc__link:focus-visible .nzp-doc__media img { transform: scale(1.05); }

.nzp-doc__body {
  display: flex;
  flex-direction: column;
  flex: 1;
  padding: var(--space-5) var(--space-6) var(--space-6);
}

.nzp-doc__date {
  display: block;
  font-size: var(--fs-xs);
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--color-secondary);
  margin-bottom: var(--space-2);
}
.nzp-doc__title {
  display: block;
  font-family: var(--font-display);
  font-size: var(--fs-lg);
  line-height: 1.25;
  margin-bottom: var(--space-3);
}
.nzp-doc__meta {
  display: block;
  font-size: var(--fs-sm);
  color: var(--color-text-muted);
  /* Pushes the call to action to the foot, so it lines up across cards whose
     descriptions run to different lengths. */
  margin-bottom: var(--space-5);
}
/* The document icon now sits with the call to action rather than heading the
   card, so the photograph can lead and the icon still says "this is a file". */
.nzp-doc__cta {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  margin-top: auto;
  padding-top: var(--space-4);
  font-size: var(--fs-sm);
  font-weight: 700;
  color: var(--color-primary);
}
.nzp-doc__cta::after { content: '\2192'; }
.nzp-doc__cta-icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 26px;
  height: 26px;
  flex: 0 0 26px;
  border-radius: 50%;
  background: var(--color-secondary-20);
}
.nzp-doc__cta-icon svg { width: 15px; height: 15px; }

/*
 * Controls appear only when there is somewhere to scroll to - with three
 * documents on a wide screen there is not. js/carousel.js sets has-overflow.
 */
.nzp-doc-shell > .nzp-carousel-arrow { display: none; }
.nzp-doc-shell.has-overflow > .nzp-carousel-arrow { display: flex; }
.nzp-doc-shell > .nzp-carousel-arrow[disabled] {
  opacity: 0.35;
  cursor: default;
  box-shadow: none;
}
.nzp-doc-shell > .nzp-carousel-arrow--prev { left: -18px; }
.nzp-doc-shell > .nzp-carousel-arrow--next { right: -18px; }

@media (max-width: 1100px) {
  .nzp-doc-shell > .nzp-carousel-arrow--prev { left: 4px; }
  .nzp-doc-shell > .nzp-carousel-arrow--next { right: 4px; }
}
@media (max-width: 640px) {
  .nzp-doc { flex-basis: 78vw; }
}


/* ==========================================================================
   LANGUAGE SWITCH (EN / DE)
   Sits immediately left of the Get in Touch button, and moves into the
   mobile panel with the CTA below 1024px.
   ========================================================================== */

.nzp-lang {
  display: inline-flex;
  align-items: center;
  gap: 2px;
  padding: 3px;
  border: 1px solid var(--color-white-20);
  border-radius: 999px;
  flex: 0 0 auto;
}
.nzp-lang__opt {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 4px 9px;
  border-radius: 999px;
  font-size: var(--fs-xs);
  font-weight: 700;
  letter-spacing: 0.06em;
  line-height: 1;
  color: rgba(255, 255, 255, 0.72);
  text-decoration: none;
  transition: background var(--transition), color var(--transition);
}
.nzp-lang__opt:hover,
.nzp-lang__opt:focus-visible { color: #FFFFFF; background: var(--color-white-20); }
.nzp-lang__opt.is-active { background: var(--color-secondary); color: var(--color-primary); }

.nzp-lang__flag {
  width: 18px;
  height: 12.6px;
  border-radius: 2px;
  display: block;
  /* The flags carry their own colours, so keep them clear of the pill tint. */
  box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.18);
}

/* In the mobile panel the switch sits above the CTA, on its own line. */
.nzp-nav__cta .nzp-lang { display: none; }

@media (max-width: 1024px) {
  .nzp-header__inner > .nzp-lang { display: none; }
  .nzp-nav__cta .nzp-lang { display: inline-flex; margin-bottom: var(--space-4); }
}

/* Phones: label only alongside the flag, kept compact. */
@media (max-width: 480px) {
  .nzp-lang__opt { padding: 4px 7px; gap: 5px; }
}


/* ==========================================================================
   PHONE LAYOUT
   --------------------------------------------------------------------------
   Deliberately the LAST block in this file. Several desktop refinements were
   written after the original responsive section, and because they carry the
   same specificity they were quietly overriding it on phones - that is how
   the Overview copy ended up in a sliver of justified text. Anything phone
   specific belongs here, at the end, where nothing can outrank it by position.

   Desktop is untouched: every rule below is inside a max-width query.
   ========================================================================== */

@media (max-width: 768px) {

  /* --- 2. Video bands: squarer, so less of the frame is cropped away ----- */
  .nzp-hero-video {
    height: auto;
    aspect-ratio: 1 / 1;
    max-height: 68vh;
    min-height: 0;
  }
  /* The banner keeps its letterbox proportion, as on desktop. Only the
     homepage intro film is square, which is what was actually asked for. */
  .nzp-page-header__subtitle { font-size: var(--fs-base); padding: 0 var(--space-5); }

  /* --- 3. Key Facts strip: smaller cards, so the next one is visible ---- */
  .nzp-kpi-carousel__track > .nzp-kpi { flex: 0 0 62vw; }
  .nzp-kpi-carousel .nzp-kpi__media { height: 150px; }
  .nzp-kpi-carousel .nzp-kpi__value { font-size: var(--fs-xl); }

  /* --- 5. Asset Management: far less air between the two cards ---------- */
  .nzp-am { padding-top: var(--space-7); padding-bottom: var(--space-7); }
  .nzp-am .nzp-grid--2 { gap: var(--space-5); }
  .nzp-am .nzp-card { padding: var(--space-5); }
  .nzp-am .nzp-card p { margin-bottom: var(--space-3); }
  .nzp-am .nzp-list { margin-bottom: 0; }

  /* --- 6. Footer: one tidy column, everything on the same left edge ----- */
  .nzp-footer__top,
  .nzp-footer__main,
  .nzp-footer__bottom {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: var(--space-4);
    text-align: left;
  }
  .nzp-footer__identity { display: flex; flex-direction: column; gap: 4px; }
  .nzp-footer__contact { display: flex; flex-direction: column; gap: 4px; align-items: flex-start; }
  .nzp-footer__links {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: var(--space-3) var(--space-5);
    width: 100%;
  }
  .nzp-footer__links li { margin: 0; }
  .nzp-footer__social { justify-content: flex-start; }

  /* --- 9 + 15. Facts two across --------------------------------------- */
  .nzp-kpi-grid,
  .nzp-kpi-grid--3 { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--space-4); }
  .nzp-kpi-grid .nzp-kpi__media { height: 110px; }
  .nzp-kpi-grid .nzp-kpi__value { font-size: var(--fs-lg); }
  .nzp-kpi-grid .nzp-kpi__label { font-size: 0.68rem; }
  .nzp-kpi-grid .nzp-kpi__body { padding: var(--space-4); }

  /* --- 10. Map and donut stay side by side, as on desktop -------------- */
  .nzp-region-split {
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
    gap: var(--space-4);
    /* start, not center: the legend column is much the taller of the two, and
       centring against it dropped the map halfway down the section. The inline
       style on the element sets center, so this has to be forced. */
    align-items: start !important;
  }
  .nzp-region-split .nzp-map--germany { margin-top: var(--space-6); }
  .nzp-region-split .nzp-donut { max-width: 150px; margin-inline: auto; }
  .nzp-region-split .nzp-legend li { gap: 6px; }
  .nzp-region-split .nzp-share__title { font-size: var(--fs-base); }
  .nzp-region-split .nzp-legend { font-size: 0.66rem; }
  .nzp-region-split .nzp-legend__swatch { width: 10px; height: 10px; }

  /* --- 12. Metrics table scrolls rather than overflowing --------------- */
  .nzp-table-scroll { overflow-x: auto; -webkit-overflow-scrolling: touch; }
  .nzp-metrics { min-width: 540px; font-size: var(--fs-xs); }
  .nzp-metrics th, .nzp-metrics td { padding: var(--space-2) var(--space-3); }
  .nzp-metric-icon { display: none; }

  /* --- 13. Strategy blocks run edge to edge, image between each -------- */
  .nzp-diagonal { display: flex; flex-direction: column; gap: var(--space-5); }
  .nzp-diagonal > * { grid-area: auto !important; width: 100%; margin: 0; }
  .nzp-diagonal__img { aspect-ratio: 16 / 10; }
  .nzp-diagonal__img img { width: 100%; height: 100%; object-fit: cover; }

  /* --- 14. Growth chart: label above its bar, bar full width ----------- */
  .nzp-chart__row { display: block; margin-bottom: var(--space-4); }
  .nzp-chart__label { display: block; width: auto; margin-bottom: 4px; font-size: var(--fs-xs); text-align: left; }
  .nzp-chart__bar-wrap { display: flex; align-items: center; gap: var(--space-2); width: 100%; }
  .nzp-chart__bar { min-width: 3px; }
  .nzp-chart__value { font-size: var(--fs-xs); white-space: nowrap; }
  .nzp-chart-panel { padding: var(--space-5); }
  .nzp-chart-legend { flex-direction: column; align-items: flex-start; gap: var(--space-2); }

  /* --- 18. SDG cards sized so one fits with the next one showing ------- */
  .nzp-sdg-card { flex: 0 0 68vw; }
  .nzp-sdg-card__band { min-height: 92px; padding: var(--space-4); gap: var(--space-3); }
  .nzp-sdg-card__num { font-size: var(--fs-2xl); }
  .nzp-sdg-card__icon { width: 34px; height: 34px; flex: 0 0 34px; }
  .nzp-sdg-card__body { padding: var(--space-4); }
  .nzp-sdg-card__body p { font-size: var(--fs-sm); }
  .nzp-sdg-head { margin-bottom: var(--space-5); }

  /* --- 20. Investor documents: no negative margins to scroll into ------ */
  .nzp-doc-slider { padding: 4px; margin: 0; }
  .nzp-doc { flex-basis: 76vw; }

  /* --- 21. Contact: envelope beside the heading, at its size ----------- */
  .nzp-contact-layout { grid-template-columns: 1fr; gap: var(--space-6); }
  .nzp-contact-aside {
    display: flex;
    flex-direction: row;
    align-items: center;
    gap: var(--space-4);
    text-align: left;
  }
  /* The envelope lives in its own 240px wrapper; that is what has to shrink. */
  .nzp-contact-aside .nzp-envelope-mark {
    width: 76px;
    flex: 0 0 76px;
    margin: 0;
  }
  .nzp-contact-aside h1 { margin: 0; font-size: var(--fs-xl); }
}


/* --- 17. Affordance: say that the circles open ---------------------------- */
.nzp-venn-hint {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  margin: 0 auto var(--space-5);
  padding: 6px var(--space-4);
  border: 1px dashed rgba(6, 31, 17, 0.28);
  border-radius: 999px;
  background: rgba(255, 255, 255, 0.55);
  font-size: var(--fs-sm);
  font-weight: 600;
  color: var(--color-text-muted);
}
.nzp-venn-hint__icon { display: inline-flex; }
.nzp-venn-hint__icon svg { width: 17px; height: 17px; }
/* One wording for pointers, another for touch. */
.nzp-venn-hint__touch { display: none; }
@media (hover: none) {
  .nzp-venn-hint__pointer { display: none; }
  .nzp-venn-hint__touch { display: inline; }
}
/* The section is centred, so the pill needs a block to centre within. */
.nzp-venn-hint { display: flex; width: max-content; max-width: 100%; }

/*
 * A slow breath on the rings until something is opened, which is what actually
 * tells people the circles are live. It stops for good on first interaction,
 * and never runs for anyone who asked for reduced motion.
 */
@keyframes nzp-venn-breathe {
  0%, 100% { stroke-opacity: 1; }
  50%      { stroke-opacity: 0.45; }
}
.nzp-venn:not(.has-opened) .nzp-venn__ring { animation: nzp-venn-breathe 2.8s ease-in-out infinite; }
.nzp-venn:not(.has-opened) .nzp-venn__group:nth-child(2) .nzp-venn__ring { animation-delay: 0.5s; }
.nzp-venn:not(.has-opened) .nzp-venn__group:nth-child(3) .nzp-venn__ring { animation-delay: 1s; }
@media (prefers-reduced-motion: reduce) {
  .nzp-venn .nzp-venn__ring { animation: none; }
}
.nzp-venn__hit { cursor: pointer; }


@media (max-width: 768px) {

  /* --- 11. Team: small portrait beside the name, bio underneath -------- */
  .nzp-team-member,
  .nzp-team-member:nth-child(even) {
    display: grid;
    grid-template-columns: 92px minmax(0, 1fr);
    /* Row 1 the name, row 2 the role; the portrait spans both. */
    grid-template-rows: auto auto;
    column-gap: var(--space-4);
    row-gap: 2px;
    padding: var(--space-5);
    min-height: 0;
  }
  .nzp-team-member__portrait,
  .nzp-team-member:nth-child(even) .nzp-team-member__portrait {
    order: 0;
    grid-column: 1;
    grid-row: 1 / span 2;
    width: 92px;
    height: 116px;
    min-height: 0;
    border-radius: var(--radius);
    overflow: hidden;
  }
  /*
   * display:contents lets the name and role become grid items in their own
   * right, so they can sit beside the portrait while the biography drops to a
   * full-width row beneath. Without it the whole text block is one cell and
   * the portrait has to be as tall as the bio.
   */
  .nzp-team-member__body { display: contents; }
  .nzp-team-member__name { grid-column: 2; grid-row: 1; align-self: end; margin: 0; font-size: var(--fs-lg); }
  .nzp-team-member__role { grid-column: 2; grid-row: 2; align-self: start; margin: 0; }
  .nzp-team-member__rule { display: none; }
  .nzp-team-member__body p { grid-column: 1 / -1; margin-bottom: var(--space-3); font-size: var(--fs-sm); }
  .nzp-team-member__body p:last-child { margin-bottom: 0; }
  .nzp-team-member__initials { font-size: 2rem; }
  .nzp-team-member__pending { display: none; }

  /* --- 16. ESG circles: bigger, and the panel opens above them --------- */
  .nzp-venn {
    display: flex;
    flex-direction: column;
    align-items: stretch;
    min-height: 0;
    max-width: none;
  }
  .nzp-venn__svg {
    order: 2;
    width: 100%;
    max-width: none;
    /* Was rendering at roughly a third of the screen; this fills the width. */
    transform: none !important;
    transition: transform var(--transition);
  }
  /*
   * The panel is a static block ABOVE the diagram rather than an overlay, so
   * opening a pillar pushes the circles down and the text lands in the frame
   * instead of off the bottom of it.
   */
  .nzp-venn-panel {
    position: static;
    order: 1;
    width: auto;
    max-width: none;
    inset: auto;
    transform: none;
    margin-bottom: var(--space-4);
    padding: var(--space-5);
    max-height: 0;
    overflow: hidden;
    opacity: 0;
    visibility: hidden;
    transition: max-height 380ms ease, opacity var(--transition), margin var(--transition);
  }
  .nzp-venn-panel.is-open {
    max-height: 1400px;
    opacity: 1;
    visibility: visible;
  }
  /* A dotted leader from the panel down to the circle it belongs to. */
  .nzp-venn-panel.is-open::after {
    content: '';
    display: block;
    width: 0;
    height: 22px;
    margin: var(--space-4) auto calc(var(--space-5) * -1);
    border-left: 2px dotted currentColor;
    opacity: 0.6;
  }
  .nzp-venn-hint { font-size: var(--fs-xs); padding: 5px var(--space-3); }

  /* --- 19. Phases stack; the drawing is handled in the block below. ---- */
  .nzp-phases { display: flex; flex-direction: column; gap: var(--space-6); }
  .nzp-house-half {
    display: block;
    width: 100%;
    aspect-ratio: 5 / 4;
    overflow: hidden;
    border-radius: var(--radius);
  }
  .nzp-house-half img {
    width: 200%;
    height: 100%;
    object-fit: cover;
    display: block;
  }
  .nzp-house-half--left  { order: 2; }
  .nzp-house-half--left img  { object-position: left center; margin-left: 0; }
  .nzp-house-half--right { order: 4; }
  .nzp-house-half--right img { object-position: right center; margin-left: -100%; }
  .nzp-phase-col--left  { order: 1; }
  .nzp-phase-col--right { order: 3; }
}

/*
 * The halves exist only for phones. Scoped as min-width rather than left as a
 * bare rule: sitting after the phone block with equal specificity, a bare
 * display:none simply cancelled it - the same later-rule-wins trap that hid
 * the Overview stacking.
 */
@media (min-width: 769px) {
  .nzp-house-half { display: none; }
}


/* ==========================================================================
   ROUND FOUR
   --------------------------------------------------------------------------
   Appended last on purpose, for the same reason the phone block above is:
   several of these correct rules written earlier in the file, and an equal
   specificity loses to whichever came later. Rules that apply to BOTH
   breakpoints sit outside a media query and are marked as such; everything
   else is inside max-width and cannot reach the desktop.
   ========================================================================== */

/* --- 5 + 9 + 12. Justified body copy. BOTH breakpoints. -------------------
   Set with hyphens:auto rather than bare justification. Justifying a narrow
   measure without hyphenation is what opens the rivers of white space that
   made this look worse than ragged right; letting the browser break words
   closes them. It needs the document language to be right, which it now is.
   Headings, figures, captions, table cells and anything centred are all left
   alone - justification belongs to running prose only.
   ------------------------------------------------------------------------ */
/* Bullets and card copy are NOT justified. Those measures are short and
   indented, and without hyphenation that is where justification tears open the
   word gaps the client is seeing ("capital allocation against"). Only wide
   running prose keeps the flush right edge. */
.nzp-text-media p,
.nzp-section-head:not(.nzp-section-head--center) p,
.nzp-container--narrow > p,
.nzp-entry-content p,
.nzp-pillar__panel p,
.nzp-venn-panel p,
.nzp-team-member__body p {
  text-align: justify;
  text-justify: inter-word;
  /* Hyphenation off, by request: no word is to be broken across a line. That
     is what opens the wider word gaps on a narrow measure - the two cannot
     both be had - so the gaps are the accepted cost of unbroken words. */
  -webkit-hyphens: manual;
  -moz-hyphens: manual;
  hyphens: manual;
  overflow-wrap: break-word;
}

/* --- 18. The SDG lead-in sat a whole section's worth of air above the cards.
   BOTH breakpoints, as asked. ---------------------------------------------- */
.nzp-sdg-head { margin-bottom: var(--space-4); }
.nzp-sdg-head p:last-child { margin-bottom: 0; }
.nzp-sdg-carousel { padding-top: var(--space-4); }

/* --- 16. The hint is an event, not furniture. BOTH breakpoints. -----------
   It rises into view when the diagram is reached, and leaves of its own
   accord after five seconds or the moment a circle is actually used. Sitting
   there permanently, it read as part of the design rather than as an
   instruction, which is why nobody followed it.
   ------------------------------------------------------------------------ */
.nzp-venn-hint {
  opacity: 0;
  transform: translateY(10px) scale(0.96);
  box-shadow: 0 6px 22px rgba(6, 31, 17, 0.16);
  background: #FFFFFF;
  border-style: solid;
  border-color: rgba(6, 31, 17, 0.14);
  transition: opacity 420ms ease, transform 420ms cubic-bezier(0.2, 0.8, 0.3, 1);
}
.nzp-venn-hint.is-visible { opacity: 1; transform: none; }
.nzp-venn-hint.is-dismissed {
  opacity: 0;
  transform: translateY(-6px) scale(0.98);
  pointer-events: none;
}
@media (prefers-reduced-motion: reduce) {
  .nzp-venn-hint { transition: opacity 200ms linear; transform: none; }
  .nzp-venn-hint.is-visible,
  .nzp-venn-hint.is-dismissed { transform: none; }
}


@media (max-width: 768px) {

  /* --- 2. Flags only, each centred in its own square.
     The switch was not merely cramped on a phone, it was being styled as a
     menu link: inside the panel it matches `.nzp-nav a`, which is one class
     and one type - stronger than a lone `.nzp-lang__opt` - and that rule
     turns it into a full-width block with 16px of padding. That is what the
     switch was glitching against. Every rule here is written through
     `.nzp-nav` so it outranks it, and the labels are gone as asked. ------- */
  .nzp-nav .nzp-lang { padding: 4px; gap: 4px; }
  .nzp-nav .nzp-lang__label,
  .nzp-lang__label { display: none; }
  .nzp-nav .nzp-lang__opt,
  .nzp-lang__opt {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 46px;
    height: 34px;
    padding: 0;
    gap: 0;
  }
  .nzp-nav .nzp-lang__flag,
  .nzp-lang__flag {
    width: 27px;
    height: 18.9px;
    flex: 0 0 27px;
    max-width: none;
  }

  /* --- 6. The frames inside the strip carried their own rounded corners, so
     the panel's dark ground showed through in the notch beside the divider -
     the "black triangles". The panel is already clipped and rounded; the
     frames inside it must not be. ----------------------------------------- */
  .nzp-slideshow--panel .nzp-slideshow__item { border-radius: 0; }
  .nzp-slideshow--panel .nzp-slideshow__track { align-items: stretch; }

  /* --- 7. Facts of one height. The cards were sized by their own text, so a
     three-word label stood a card taller than a one-word one. The row now
     sets the height and each card fills it. ------------------------------- */
  .nzp-kpi-grid { grid-auto-rows: 1fr; }
  /*
   * height:100% is what stopped align-items:stretch working on the strip: a
   * percentage height against an auto-height flex line resolves to auto, so
   * every card kept its own content height - 259px to 306px across the six.
   * The grid still wants it, because a 1fr row IS a definite height. The
   * carousel must not have it.
   */
  .nzp-kpi-grid .nzp-kpi {
    display: flex;
    flex-direction: column;
    height: 100%;
  }
  .nzp-kpi-carousel__track > .nzp-kpi {
    display: flex;
    flex-direction: column;
    height: auto;
    align-self: stretch;
  }
  .nzp-kpi-carousel__track { align-items: stretch; }
  .nzp-kpi-grid .nzp-kpi__media { flex: 0 0 110px; }
  .nzp-kpi-carousel .nzp-kpi__media { flex: 0 0 150px; }
  .nzp-kpi-grid .nzp-kpi__body,
  .nzp-kpi-carousel .nzp-kpi__body {
    flex: 1 1 auto;
    display: flex;
    flex-direction: column;
    gap: 6px;
  }
  /*
   * Last round reserved two lines for the figure with a flex box and pushed
   * the label to the bottom with margin-top:auto. Both were wrong: a flex
   * container ignores the card's text-align, so "~15.5k" went hard left while
   * its neighbours stayed centred, and the auto margin drove the label to the
   * foot of the card with a gulf above it. The body is centred as a group
   * instead, which keeps every line centred and the pair together.
   */
  .nzp-kpi-grid .nzp-kpi__body,
  .nzp-kpi-carousel .nzp-kpi__body {
    justify-content: center;
    text-align: center;
    padding: var(--space-4) var(--space-3);
  }
  .nzp-kpi-grid .nzp-kpi__value,
  .nzp-kpi-carousel .nzp-kpi__value {
    display: block;
    line-height: 1.15;
  }
  .nzp-kpi-grid .nzp-kpi__label,
  .nzp-kpi-carousel .nzp-kpi__label {
    display: block;
    margin-top: 6px;
    line-height: 1.25;
  }

  /*
   * The brand rule moves from the top of the card to the top of the text
   * block. It was on every card already - measured, not assumed - but at the
   * top it lands on whatever the media happens to be: stark over the dark map,
   * invisible over a bright sky, muted over the pale drawn panels. Which is
   * why it read as though only some cards had it. Against the text block it is
   * the same rule on the same white ground on all six, and it does the useful
   * job of separating the picture from the figure.
   */
  .nzp-kpi-grid .nzp-kpi,
  .nzp-kpi-carousel__track > .nzp-kpi { border-top-color: transparent; }
  .nzp-kpi-grid .nzp-kpi__body,
  .nzp-kpi-carousel .nzp-kpi__body { border-top: 3px solid var(--color-secondary); }

  /* --- 8. Map, donut and key as one square block. The key was set at almost
     body size and ran taller than the map beside it. ---------------------- */
  /* The map takes the larger share and the whole cluster is held to roughly
     a square, so the chart and the key read as annotations to it rather than
     as two more things competing for the same attention. */
  .nzp-region-split {
    grid-template-columns: minmax(0, 1.45fr) minmax(0, 1fr);
    gap: var(--space-2);
    align-items: center !important;
    max-width: 430px;
    margin-inline: auto;
  }
  .nzp-region-split .nzp-map--germany { margin-top: 0; }
  .nzp-region-split .nzp-map--germany svg { max-height: 340px; width: 100%; height: auto; }
  .nzp-region-split .nzp-share__title {
    font-size: 0.66rem;
    line-height: 1.2;
    margin-bottom: var(--space-2);
  }
  .nzp-region-split .nzp-donut { max-width: 86px; margin-inline: auto; }
  /* The key was setting the height of the whole cluster - five items at about
     48px each ran it 76px taller than it was wide. Trimmed to roughly 30px an
     item, the map, the chart and the key together come out square. */
  .nzp-region-split .nzp-legend {
    font-size: 0.52rem;
    line-height: 1.15;
    margin-top: var(--space-2);
    padding: var(--space-2) var(--space-2) 4px;
  }
  .nzp-region-split .nzp-legend li {
    gap: 4px;
    margin-bottom: 0;
    padding: 3px 0;
    min-height: 0;
  }
  .nzp-region-split .nzp-legend li + li { border-top: 0; }
  .nzp-region-split .nzp-legend__swatch { width: 7px; height: 7px; flex: 0 0 7px; }
  .nzp-region-split .nzp-legend__name { line-height: 1.15; }

  /* --- 10. The team read flat because the name and the role were nearly the
     same size. Desktop already separates them; this matches it. ----------- */
  .nzp-team-member__name {
    font-size: 1.18rem;
    font-weight: 700;
    line-height: 1.15;
    letter-spacing: -0.01em;
  }
  .nzp-team-member__role {
    font-size: 0.72rem;
    font-weight: 600;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    opacity: 0.72;
  }
  /* The portrait gets a frame, and the name block is separated from the
     biography by a rule, so the two stop running into each other. */
  .nzp-team-member__portrait,
  .nzp-team-member:nth-child(even) .nzp-team-member__portrait {
    border: 1px solid var(--color-border);
    border-radius: var(--radius);
    background: var(--color-bg-alt);
  }
  .nzp-team-member,
  .nzp-team-member:nth-child(even) { column-gap: var(--space-5); }
  .nzp-team-member__body p:first-of-type {
    border-top: 1px solid var(--color-border);
    margin-top: var(--space-4);
    padding-top: var(--space-4);
  }

  /* --- 13. The metrics table does scroll, but nothing said so. A shadow that
     sits over the right edge until you reach the end is the usual way to say
     it, and it costs no space. ------------------------------------------- */
  .nzp-table-scroll {
    position: relative;
    background:
      linear-gradient(to right, var(--color-bg-alt) 30%, rgba(255, 255, 255, 0)) left center,
      linear-gradient(to left,  var(--color-bg-alt) 30%, rgba(255, 255, 255, 0)) right center,
      radial-gradient(farthest-side at 0 50%, rgba(6, 31, 17, 0.22), rgba(6, 31, 17, 0)) left center,
      radial-gradient(farthest-side at 100% 50%, rgba(6, 31, 17, 0.22), rgba(6, 31, 17, 0)) right center;
    background-repeat: no-repeat;
    background-size: 44px 100%, 44px 100%, 16px 100%, 16px 100%;
    background-attachment: local, local, scroll, scroll;
  }

  /* --- 14. The growth chart. Eight rows at a section's spacing each ran the
     exhibit off the screen; and the mark belongs on it, in the corner, the
     way it does on desktop. ---------------------------------------------- */
  /* The card sat inside the panel inside the container - 64px of inset on
     each side before a bar could start, which is what made it look squeezed
     into the middle. Trimmed, the bars gain about 45% more length. */
  .nzp-chart-panel { padding: var(--space-3); }
  .nzp-chart-panel__mark {
    display: block;
    top: var(--space-3);
    right: var(--space-3);
    width: 30px;
    opacity: 0.45;
  }
  .nzp-chart { padding: var(--space-5) var(--space-3) var(--space-3); }
  /* "Portfolio Evolution" sat a whole section away from the page title. */
  .nzp-section-head { margin-bottom: var(--space-4); }
  .nzp-section-head + .nzp-case-head { margin-top: 0; }
  .nzp-case-head { margin-bottom: var(--space-4); }
  /* The label sits on the same line as the bar rather than above it, which is
     what was doubling every row's height. */
  .nzp-chart__row {
    display: grid;
    grid-template-columns: 44px minmax(0, 1fr);
    align-items: center;
    gap: 6px;
    margin-bottom: 3px;
  }
  .nzp-chart__label {
    display: block;
    margin: 0;
    font-size: 0.64rem;
    opacity: 0.8;
    text-align: left;
  }
  .nzp-chart__bar { height: 20px; }
  .nzp-chart__value { font-size: 0.68rem; }

  /* --- 15. The two facts side by side, as one row. --------------------- */
  .nzp-today { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--space-4); }
  .nzp-today__row {
    display: flex;
    flex-direction: column;
    gap: var(--space-3);
    border-bottom: 0;
    padding: 0;
  }
  .nzp-today__media { order: -1; aspect-ratio: 4 / 3; border-radius: var(--radius); overflow: hidden; }
  .nzp-today__text { display: flex; flex-direction: column; gap: 2px; }
  .nzp-today__value { font-size: var(--fs-lg); }
  .nzp-today__label { font-size: 0.66rem; letter-spacing: 0.08em; }

  /* --- 17. The circles were about a third of the screen. The diagram's own
     artwork stops well inside its viewBox - 62 units of empty margin either
     side of 620 - so it can be pulled out to the screen edges and then over
     them by that same 10% without a single stroke being clipped. Together
     that is about a third larger. ---------------------------------------- */
  /*
   * Last round made the circles bigger by pushing the SVG 10% past each edge -
   * but the SVG *is* the frosted panel, border and all, so the panel went off
   * the screen with it. The panel now runs exactly to both edges and the
   * circles are enlarged where they should have been in the first place: by
   * cropping the viewBox to the artwork (see page-sustainability.php) and by
   * taking most of the panel's inner padding back.
   */
  /*
   * width:auto, not the inherited width:100%. A percentage width resolves
   * against the container's CONTENT box, so the negative margins slid the
   * panel left without making it any wider - which is why it sat 16px off
   * centre with a gap down the right-hand side. Letting the width be auto lets
   * the margins do what they were written to do and the panel reaches both
   * edges.
   */
  .nzp-venn {
    width: auto;
    max-width: none;
    margin-inline: calc(var(--space-4) * -1);
  }
  .nzp-venn__svg {
    width: 100%;
    max-width: none;
    margin-left: 0;
    padding: var(--space-2);
    border-radius: 14px;
  }
  .nzp-venn-panel { margin-inline: var(--space-4); }

  /* --- 16 (phone half). The leader from the panel down to the circle it
     belongs to. It was already written, but hung on a negative margin
     underneath a panel that clips its own overflow, so it was never once
     drawn. Kept inside the padding box, it shows. ------------------------ */
  .nzp-venn-panel.is-open::after {
    content: '';
    display: block;
    width: 0;
    height: 26px;
    margin: var(--space-4) auto 0;
    border-left: 2px dotted currentColor;
    opacity: 0.65;
  }

  /* --- 19. Centring is done by js/carousel.js, which moves the track to the
     offset that puts a chosen card in the middle. Nothing here needs to
     scroll-snap, and the strip must be draggable sideways while the page
     still scrolls up and down - which is what pan-y grants. ------------- */
  .nzp-sdg-carousel,
  .nzp-kpi-carousel,
  .nzp-carousel,
  .nzp-slideshow { touch-action: pan-y; }

  /* --- 21. One drawing, cut down the middle. Phase 1's half sits to the
     right of Phase 1's text; Phase 2's half to the left of Phase 2's. The
     ratio is the real one - the artwork is 820 x 1187, so each half is
     410 x 1187 - which is what makes it a clean cut rather than a slice
     through the middle of the building. --------------------------------- */
  /* Five tracks rather than two, so the split can be 60/40 in favour of the
     reading column on BOTH rows. A two-track grid shares its widths between
     rows, so any ratio that helped Phase 1 squeezed Phase 2 by the same
     amount; spanning three tracks of five gets the text the wider side each
     time while the halves stay the same size as one another. */
  .nzp-phases {
    display: grid;
    grid-template-columns: repeat(5, minmax(0, 1fr));
    gap: var(--space-5) var(--space-3);
    align-items: center;
  }
  .nzp-phase-col--left   { grid-column: 1 / 4; grid-row: 1; }
  .nzp-house-half--left  { grid-column: 4 / 6; grid-row: 1; }
  .nzp-house-half--right { grid-column: 1 / 3; grid-row: 2; }
  .nzp-phase-col--right  { grid-column: 3 / 6; grid-row: 2; }
  .nzp-house { display: none; }
  /* Each half is its own file, cut on the drawing's own line and padded to a
     common frame, so there is nothing left to crop here: show it whole. */
  .nzp-house { display: none; }
  .nzp-house-half {
    display: block;
    width: 100%;
    overflow: visible;
  }
  .nzp-house-half img {
    display: block;
    width: 100%;
    height: auto;
    max-width: 100%;
    margin: 0;
  }
  .nzp-phase-step { margin-bottom: var(--space-3); }
  .nzp-phase-step__text { font-size: var(--fs-xs); }

  /* --- 22. The contact card is a footnote to the reports, not a headline
     beside them: smaller, and after the thing it refers to. The head is
     dissolved so its two halves become items of the container itself, which
     is the only way one of them can be ordered past a different block. --- */
  .nzp-container:has(> .nzp-doc-shell) { display: flex; flex-direction: column; }
  .nzp-investors-head { display: contents; }
  /* display:contents on the wrapper drops its own spacing along with its box,
     so the gap under the heading has to be restated here. */
  .nzp-investors-head__intro { order: 1; margin-bottom: var(--space-5); }
  .nzp-doc-shell { order: 2; }
  .nzp-credit-contact { order: 3; margin-top: var(--space-6); }
  .nzp-credit-contact { padding: var(--space-4); }
  .nzp-credit-contact__title { font-size: 0.72rem; letter-spacing: 0.1em; margin-bottom: var(--space-3); }
  .nzp-credit-contact__person { flex-direction: row; align-items: center; gap: var(--space-3); }
  .nzp-credit-contact__portrait { width: 52px; height: 52px; flex: 0 0 52px; }
  .nzp-credit-contact__name { font-size: var(--fs-base); }
  .nzp-credit-contact__role { font-size: var(--fs-xs); }

  /*
   * The page could be dragged sideways into blank space: the shell let its
   * contents spill and nothing above it clipped, so the document measured
   * 737px against a 375px screen. It clips its own overflow now (below).
   */

  /*
   * Centring the first and last card needs side padding of exactly half the
   * leftover space. Percentages cannot express that: a percentage flex-basis
   * resolves against the rail's CONTENT box, which is the rail minus the very
   * padding being solved for, and the algebra collapses. So the rail is made
   * full-bleed - its width becomes the viewport's - and both the card and the
   * padding are stated in vw, where they refer to the same thing:
   *   card 78vw, padding (100 - 78) / 2 = 11vw.
   */
  .nzp-doc-shell {
    margin-inline: calc(var(--space-4) * -1);
    overflow-x: clip;
    /* Makes the rail itself the unit of measure for everything inside it. */
    container-type: inline-size;
  }
  /*
   * cqw, not vw. 100vw counts the scrollbar gutter; the rail does not have it,
   * so on any browser that shows a scrollbar the padding came out about 8px
   * wider than half the leftover and the end cards stopped short of the
   * middle. 1cqw is one per cent of the rail, which is exactly the box the
   * card is being centred in. The vw line stays first as a fallback for
   * anything too old for container units.
   */
  /*
   * The side space is put on the TRACK, not on the scroller. A scroll
   * container's trailing padding is left out of its scrollable area, so with
   * the padding on the scroller the strip ran out of travel one padding-width
   * early and the last card came to rest hard right instead of centred - out
   * by exactly the 41px of padding. As part of the track it is content, and
   * counts at both ends.
   */
  .nzp-doc-slider {
    scroll-snap-type: x mandatory;
    scroll-padding-inline: 0;
    padding-inline: 0;
  }
  /*
   * Spacers as real flex items rather than padding. Padding on the scroller is
   * dropped from its scrollable area at the trailing edge, and padding on the
   * track was not counted either; a flex child is a box the layout cannot
   * argue with, so the travel is right at both ends.
   */
  .nzp-doc-track { padding-inline: 0; }
  .nzp-doc-track::before,
  .nzp-doc-track::after {
    content: '';
    flex: 0 0 11vw;
    flex: 0 0 11cqw;
    align-self: stretch;
  }
  .nzp-doc {
    flex: 0 0 78vw;
    flex: 0 0 78cqw;
    scroll-snap-align: center;
  }

  /* --- 25. The footer's page list is a second copy of the menu that is
     already one tap away in the header, and stacked two-up on a phone it was
     the largest thing in the footer. ------------------------------------ */
  .nzp-footer__nav { display: none; }
  .nzp-footer__widgets { display: none; }
}



/* The Asset Management backdrops, chosen by width. The URLs arrive as custom
   properties on the element so that a media query can still decide, which an
   inline background-image would not allow. */
.nzp-am__bg { background-image: var(--nzp-bg); }
@media (max-width: 768px) {
  .nzp-am__bg { background-image: var(--nzp-bg-small, var(--nzp-bg)); }
}


/* ==========================================================================
   ROUND FIVE
   ========================================================================== */

/* --- 14. The hint sits ON the diagram, not stacked above it. BOTH.
   Above the circles it read as a caption belonging to the heading, and it was
   holding a band of empty space between the two. It is inside .nzp-venn now
   (see page-sustainability.php) and floats over the top of the panel. ------ */
.nzp-venn { position: relative; }
.nzp-venn-hint {
  position: absolute;
  top: var(--space-4);
  inset-inline: 0;
  z-index: 4;
  margin: 0 auto;
  width: max-content;
  max-width: calc(100% - var(--space-6));
}

/* --- 14. And the band of air above the circles goes with it. BOTH. ------- */
.nzp-esg-section { padding-top: var(--space-6); }

/* --- 11. Controls under the wide table. They appear only when there is
   somewhere to scroll, which js/navigation.js decides by measurement. ----- */
.nzp-table-nav {
  display: none;
  justify-content: center;
  gap: var(--space-3);
  margin-top: var(--space-4);
}
.nzp-table-nav.is-needed { display: flex; }
.nzp-table-nav__btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 40px;
  height: 40px;
  padding: 0;
  border: 1px solid var(--color-border);
  border-radius: 50%;
  background: var(--color-bg);
  color: var(--color-primary);
  cursor: pointer;
  transition: background var(--transition), opacity var(--transition);
}
.nzp-table-nav__btn svg {
  width: 18px;
  height: 18px;
  fill: none;
  stroke: currentColor;
  stroke-width: 2.2;
  stroke-linecap: round;
  stroke-linejoin: round;
}
.nzp-table-nav__btn:hover:not([disabled]) { background: var(--color-bg-alt); }
.nzp-table-nav__btn[disabled] { opacity: 0.35; cursor: default; }
.nzp-table-nav__btn:focus-visible { outline: 2px solid var(--color-secondary); outline-offset: 2px; }


@media (max-width: 1024px) {
  /* --- 1 + 4. The switch and the button share a row with real space between
     them, instead of sitting stacked and almost touching. --------------- */
  .nzp-nav__cta {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-6);
    padding: var(--space-5) var(--space-4);
  }
  .nzp-nav__cta .nzp-lang { margin-bottom: 0; flex: 0 0 auto; }
  .nzp-nav__cta .nzp-btn--nav { flex: 0 0 auto; margin: 0; }
}


@media (max-width: 768px) {

  /* --- 5. It is a heading, so it is sized like one. ------------------- */
  .nzp-page-header__subtitle {
    font-size: 1.86rem;
    line-height: 1.18;
    font-weight: 700;
    letter-spacing: -0.015em;
    padding: 0 var(--space-3);
  }

  /* --- 18. The portrait is a portrait: upright, as on the team page, not
     the square it had been cropped into. ------------------------------- */
  .nzp-credit-contact__portrait {
    width: 54px;
    height: 70px;
    flex: 0 0 54px;
    border-radius: var(--radius);
    overflow: hidden;
  }
  .nzp-credit-contact__portrait img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    object-position: center top;
  }

  /* --- 15. The hint, over a panel that now reaches both screen edges. -- */
  .nzp-venn-hint {
    top: var(--space-3);
    font-size: var(--fs-xs);
    padding: 5px var(--space-3);
  }
}


/* --- 1. Never show a play badge on the background films -------------------
   Two different badges were appearing. One was mine, added last round so a
   blocked film could still be started; it is gone. The other is drawn by iOS
   itself over any video it has not begun - that is the one that survived every
   previous attempt, because it is browser chrome rather than anything in the
   page. It is suppressed here.

   Scoped to video[autoplay] on purpose: the Manage-to-Green programme film
   carries real controls and must keep every one of them. */
video[autoplay]::-webkit-media-controls,
video[autoplay]::-webkit-media-controls-enclosure,
video[autoplay]::-webkit-media-controls-panel,
video[autoplay]::-webkit-media-controls-start-playback-button,
video[autoplay]::-webkit-media-controls-play-button,
video[autoplay]::-webkit-media-controls-overlay-play-button {
  display: none !important;
  -webkit-appearance: none;
  appearance: none;
  opacity: 0 !important;
}
/* A tap on the film still starts it; js/navigation.js listens for that. */
video[autoplay] { cursor: default; }


/* --- 2. The heading must sit above the band's bottom fade -----------------
   .nzp-page-header--video::after lays a 130px gradient over the foot of the
   band so it dissolves into the section below. It carries z-index 2 and the
   text block did not carry one at all, so on a 200px-tall banner the gradient
   was painted straight over the last two lines - the "blurred out" bottom. */
.nzp-page-header__overlay { z-index: 3; }


/* --- 3. No focus box on the ESG circles ----------------------------------
   The hit areas are focusable, so a tap left the browser's default ring - a
   blue square around a circle. Keyboard users still get a ring, because
   :focus-visible fires for them and not for a pointer. */
.nzp-venn__hit:focus { outline: none; }
.nzp-venn__hit:focus-visible {
  outline: 2px solid var(--color-secondary);
  outline-offset: 2px;
}
.nzp-venn__group:focus,
.nzp-venn__svg:focus { outline: none; }


/* --- 4. The EPC progression chart is a diagram, not a photograph ----------
   It sits in the diagonal layout under "Two-Phase Programme", in a slot built
   for photographs: a 16:10 frame filled with object-fit:cover. The drawing is
   760x300 - two and a half times as wide as it is tall - so cover scaled it to
   the frame's height and cut the ends off, taking the red E it starts from and
   the green A it finishes at with them. A diagram has to be shown whole.
   Applies at every width; the crop was there on the desktop too. */
.nzp-diagonal__img--graphic {
  /* No fixed frame at all - the drawing sets its own height, so there is
     neither a crop nor a band of empty space above and below it. */
  aspect-ratio: auto;
  height: auto;
  min-height: 0;
  background: transparent;
  overflow: visible;
  align-self: center;
}
.nzp-diagonal__img--graphic img {
  width: 100%;
  height: auto;
  object-fit: contain;
  object-position: center;
}


/* ==========================================================================
   HOMEPAGE INTRODUCTION
   The first words after the film. It carries the whole proposition, so it is
   set above body size and held to a reading measure rather than running the
   full container width, which at 1200px would be roughly 150 characters a
   line and read as a wall.
   ========================================================================== */
.nzp-intro {
  padding: var(--space-8) 0 var(--space-7);
  background: var(--color-bg);
}
.nzp-intro__inner { max-width: 940px; }

.nzp-intro__lead {
  margin-bottom: var(--space-5);
  font-family: var(--font-display);
  font-size: var(--fs-xl);
  font-weight: 600;
  line-height: 1.32;
  letter-spacing: -0.015em;
  color: var(--color-text);
}

.nzp-intro__body {
  margin-bottom: var(--space-4);
  font-size: var(--fs-md);
  line-height: 1.7;
  color: var(--color-text-muted);
}
.nzp-intro__body:last-child { margin-bottom: 0; }

/* Manage-to-Green carries the site's standard inline link treatment. */
.nzp-intro__body a {
  color: var(--color-text);
  font-weight: 600;
  text-decoration: underline;
  text-decoration-color: var(--color-secondary);
  text-decoration-thickness: 2px;
  text-underline-offset: 3px;
}
.nzp-intro__body a:hover,
.nzp-intro__body a:focus-visible { text-decoration-color: var(--color-primary); }


/* ==========================================================================
   VERTICAL COLUMN CHART
   Counterpart to .nzp-chart. Used on Track Record for the vacancy series and
   the GAV progression, where the reading is chronological and so runs left to
   right rather than top to bottom.

   The axis is the plot's own bottom border. Each column owns a segment of it,
   and because the columns are adjacent those segments join into one line, so
   there is no separate axis element to keep in register with the bars.
   ========================================================================== */
.nzp-excellence {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--space-5);
  align-items: stretch;
}
.nzp-excellence__col {
  display: flex;
  flex-direction: column;
  gap: var(--space-5);
  min-width: 0;
}

/*
 * flex: 1 on the panels lets the shorter column absorb the height of the
 * taller one, so the two sides finish level whatever the chart heights are.
 */
.nzp-vchart-panel {
  display: flex;
  flex-direction: column;
  flex: 1;
  min-width: 0;
}
.nzp-vchart-panel .nzp-case-head { margin-bottom: var(--space-6); }
.nzp-vchart-panel .nzp-case-head h3 {
  font-size: var(--fs-lg);
  line-height: 1.3;
}

/*
 * No gap between the columns. Each column draws its own segment of the axis
 * as a bottom border, and a gap would break that line into dashes under the
 * bars. The bars are spaced by their own max-width instead, which keeps the
 * axis continuous however many columns a chart has.
 */
.nzp-vchart {
  display: flex;
  flex-direction: column;
  flex: 1;
  min-width: 0;
}
.nzp-vchart__plots {
  display: flex;
  align-items: stretch;
  flex: 1;
  min-width: 0;
}
.nzp-vchart__labels {
  display: flex;
  min-width: 0;
}

/*
 * The bars are anchored to the bottom of this box, and its height is what the
 * percentages resolve against. min-height keeps a short chart from collapsing
 * when the grid has no surplus height to hand out.
 */
.nzp-vchart__plot {
  display: flex;
  flex: 1;
  align-items: flex-end;
  justify-content: center;
  min-width: 0;
  min-height: 168px;
  border-bottom: 1px solid var(--color-border);
}
.nzp-vchart--tall .nzp-vchart__plot { min-height: 392px; }

.nzp-vchart__bar {
  position: relative;
  width: 100%;
  max-width: 68px;
  min-height: 4px;
  border-radius: 3px 3px 0 0;
  background: linear-gradient(180deg, #4C7C5D 0%, var(--color-primary) 100%);
  transition: height 900ms cubic-bezier(0.22, 1, 0.36, 1);
}

/*
 * Sat above the bar rather than inside it: the shortest bar here is 3.1%, and
 * a figure printed inside it would not fit.
 */
.nzp-vchart__value {
  position: absolute;
  bottom: 100%;
  left: 50%;
  transform: translateX(-50%);
  margin-bottom: var(--space-2);
  font-family: var(--font-display);
  font-size: var(--fs-base);
  font-weight: 700;
  color: var(--color-text);
  white-space: nowrap;
}

.nzp-vchart__label {
  flex: 1;
  min-width: 0;
  margin-top: var(--space-3);
  font-size: var(--fs-sm);
  font-weight: 600;
  line-height: 1.3;
  color: var(--color-text-muted);
  text-align: center;
  overflow-wrap: break-word;
}


@media (max-width: 768px) {

  .nzp-intro { padding: var(--space-7) 0 var(--space-6); }
  .nzp-intro__lead { font-size: var(--fs-lg); }
  .nzp-intro__body { font-size: var(--fs-base); }

  /*
   * One chart per row. The GAV chart no longer has a neighbour to match, so
   * its plot drops back to the standard height rather than filling half a
   * phone screen on its own.
   */
  .nzp-excellence { grid-template-columns: 1fr; }
  .nzp-vchart--tall .nzp-vchart__plot { min-height: 200px; }
  .nzp-vchart__plot { min-height: 160px; }
  .nzp-vchart__bar { max-width: 52px; }
  /*
   * The GAV chart puts five figures over five narrow bars. At --fs-sm they
   * touch; at --fs-xs they clear each other with room to spare.
   */
  .nzp-vchart__value { font-size: var(--fs-xs); }
  .nzp-vchart__label { font-size: var(--fs-xs); }
  .nzp-vchart-panel .nzp-case-head h3 { font-size: var(--fs-md); }

}


/*
 * The intro's running prose joins the rest of the site's wide prose in being
 * justified. Desktop only, matching the rule above: on a phone measure this
 * is what tears the word gaps open, so it stays ragged there.
 *
 * The lead is excluded. It is a display statement rather than running text,
 * and it is set at heading size, where justification shows badly.
 */
@media (min-width: 769px) {
  .nzp-intro__body {
    text-align: justify;
    text-justify: inter-word;
    hyphens: none;
  }
}


/* ==========================================================================
   ROUND TEN
   ========================================================================== */

/* 1. The opening statement is centred; the paragraphs under it are not. */
.nzp-intro__lead { text-align: center; }

/*
 * 2. The chart titles live in a <figcaption>, and the base stylesheet sets
 * every figcaption in italic at caption size. That treatment is for photo
 * captions; here the element is the chart's heading, so it is reset.
 */
.nzp-vchart-panel figcaption {
  margin-top: 0;
  font-style: normal;
  font-size: inherit;
  color: inherit;
}

/*
 * The panels pick up the same hover as the document and press cards: a small
 * lift, a sand border and a soft shadow.
 */
.nzp-vchart-panel {
  border-color: var(--color-light-dark);
  transition: border-color var(--transition), box-shadow var(--transition),
              transform var(--transition);
}
.nzp-vchart-panel:hover,
.nzp-vchart-panel:focus-within {
  border-color: var(--color-secondary);
  box-shadow: 0 12px 30px rgba(6, 31, 17, 0.13);
  transform: translateY(-4px) scale(1.008);
}

@media (prefers-reduced-motion: reduce) {
  .nzp-vchart-panel:hover,
  .nzp-vchart-panel:focus-within { transform: none; }
}

/*
 * 3. The investor slider's arrows used to sit at -18px, which is less than
 * their own 48px width, so two thirds of each one covered the first and last
 * card. The shell now reserves a gutter and the arrows sit in it, clear of the
 * cards. A negative offset would put them in the page margin instead, but that
 * margin runs out at around 1210px and the page would start scrolling
 * sideways; a reserved gutter holds at every width.
 */
@media (min-width: 769px) {
  .nzp-doc-shell.has-overflow {
    padding-left: 72px;
    padding-right: 72px;
  }
  .nzp-doc-shell.has-overflow > .nzp-carousel-arrow--prev { left: 6px; }
  .nzp-doc-shell.has-overflow > .nzp-carousel-arrow--next { right: 6px; }
}


/* ==========================================================================
   ROUND ELEVEN
   ========================================================================== */

/* --- Homepage introduction, moved here from About Us --------------------- */
/*
 * The three paragraphs are now framed cards rather than running prose. The
 * rule that justified .nzp-intro__body no longer applies: these are short,
 * boxed measures, which is exactly where justification tears the word gaps.
 */
.nzp-intro__frames {
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
}

.nzp-intro__frame {
  position: relative;
  margin: 0;
  padding: var(--space-5) var(--space-5) var(--space-5) var(--space-6);
  background: var(--color-bg);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-lg);
  box-shadow: 0 1px 2px rgba(6, 31, 17, 0.04);
  font-size: var(--fs-base);
  line-height: 1.65;
  color: var(--color-text-muted);
  text-align: left;
  transition: border-color var(--transition), box-shadow var(--transition),
              transform var(--transition);
}

/*
 * A sand spine down the left edge, drawn inside the rounded corner rather than
 * as a border-left, which would square the card off at top and bottom.
 */
.nzp-intro__frame::before {
  content: '';
  position: absolute;
  top: var(--space-5);
  bottom: var(--space-5);
  left: var(--space-4);
  width: 3px;
  border-radius: 2px;
  background: var(--color-secondary);
}

/*
 * These are <p> inside .nzp-text-media, which is justified on desktop. Only
 * the alignment is overridden here, and at the specificity needed to win.
 * Setting the whole base rule at this weight would outrank --lead and the
 * phone block, both of which are single-class selectors.
 */
.nzp-text-media .nzp-intro__frame { text-align: left; }

.nzp-intro__frame:hover {
  border-color: var(--color-secondary);
  box-shadow: 0 10px 26px rgba(6, 31, 17, 0.10);
  transform: translateY(-2px);
}

/* The opening statement carries the weight; the two after it support it. */
.nzp-intro__frame--lead {
  font-family: var(--font-display);
  font-size: var(--fs-lg);
  font-weight: 600;
  line-height: 1.4;
  letter-spacing: -0.01em;
  color: var(--color-text);
  background: var(--color-bg-alt);
}
.nzp-intro__frame--lead::before { background: var(--color-primary); }

.nzp-intro__frame a {
  color: var(--color-text);
  font-weight: 600;
  text-decoration: underline;
  text-decoration-color: var(--color-secondary);
  text-decoration-thickness: 2px;
  text-underline-offset: 3px;
}
.nzp-intro__frame a:hover,
.nzp-intro__frame a:focus-visible { text-decoration-color: var(--color-primary); }


/* --- Track Record: pace and contrast ------------------------------------- */
/*
 * The chart card is the same grey as an alternating section, so on a tinted
 * band it vanished. On tinted ground the card goes white instead, which also
 * makes it read more like a published exhibit than it did on white.
 */
.nzp-section--alt .nzp-chart-panel { background: var(--color-bg); }

/*
 * Two full sections meeting means 4rem of padding from each. Under a chart
 * that already carries its own generous padding, 8rem of empty white read as
 * a break in the page rather than a gap between sections.
 */
.nzp-excellence-section { padding-top: var(--space-6); }


/* --- Chart titles: their own frame ---------------------------------------- */
.nzp-vchart-panel .nzp-case-head {
  margin: calc(var(--space-4) * -1) calc(var(--space-2) * -1) var(--space-6);
  padding: var(--space-4) var(--space-5);
  background: var(--color-bg);
  border: 1px solid var(--color-border);
  border-radius: var(--radius);
}
.nzp-vchart-panel .nzp-case-head h3 { margin: 0; }
/* On a tinted section the panel is white, so the title needs the tint. */
.nzp-section--alt .nzp-vchart-panel .nzp-case-head { background: var(--color-bg-alt); }


/* --- Second line under an axis label -------------------------------------- */
.nzp-vchart__sub {
  display: block;
  font-weight: 500;
  font-size: 0.9em;
  opacity: 0.8;
}


/* --- Energy traces between the charts ------------------------------------- */
/*
 * The slot is the panel's box and is never transformed, so a trace anchored to
 * it holds its position while the panel lifts on hover.
 */
.nzp-excellence { position: relative; }
.nzp-excellence__slot {
  position: relative;
  display: flex;
  flex: 1;
  min-width: 0;
}
.nzp-excellence__slot > .nzp-vchart-panel { flex: 1; }

.nzp-spark {
  position: absolute;
  display: block;
  pointer-events: none;
  z-index: 1;
}
.nzp-spark svg { display: block; width: 100%; height: 100%; overflow: visible; }

/* Left panel to the value chart, across the column gap. */
.nzp-spark--right {
  top: 50%;
  left: 100%;
  width: var(--space-8);
  height: 44px;
  transform: translateY(-50%);
}
/* Top-left panel down to the one below it, through the row gap. */
.nzp-spark--down {
  left: 50%;
  top: 100%;
  width: 44px;
  height: var(--space-7);
  transform: translateX(-50%);
}

.nzp-spark__glow {
  stroke-width: 7;
  stroke-linecap: round;
  opacity: 0.22;
}
.nzp-spark__flow {
  stroke-width: 2.4;
  stroke-linecap: round;
  stroke-dasharray: 7 9;
  animation: nzp-spark-flow 1.8s linear infinite;
}
@keyframes nzp-spark-flow {
  from { stroke-dashoffset: 32; }
  to   { stroke-dashoffset: 0; }
}
@media (prefers-reduced-motion: reduce) {
  .nzp-spark__flow { animation: none; }
}

/* The gaps the traces run through have to be wide enough to hold them. */
@media (min-width: 769px) {
  .nzp-excellence { gap: var(--space-8); }
  .nzp-excellence__col { gap: var(--space-7); }
}


@media (max-width: 768px) {
  /* The charts stack, so there is no gap for a trace to cross. */
  .nzp-spark { display: none; }

  .nzp-intro__frame { padding: var(--space-4) var(--space-4) var(--space-4) var(--space-5); }
  .nzp-intro__frame::before { top: var(--space-4); bottom: var(--space-4); left: var(--space-3); }
  .nzp-intro__frame--lead { font-size: var(--fs-md); }
  .nzp-vchart-panel .nzp-case-head { padding: var(--space-3) var(--space-4); }
}


/* The terminals sit on the panel edges; they do not need the flow animation. */
.nzp-spark__node { opacity: 0.55; }


/* ==========================================================================
   ROUND THIRTEEN
   ========================================================================== */

/* --------------------------------------------------------------------------
   1. HOMEPAGE INTRODUCTION
   Wider band, cards that run wide rather than tall, and an icon on each.
   -------------------------------------------------------------------------- */
.nzp-container--wide { max-width: 1400px; }

/*
 * stretch, not center: the photography column is asked to match the height of
 * the copy beside it, which only works if the grid hands it the row height.
 */
.nzp-intro .nzp-text-media {
  align-items: stretch;
  gap: var(--space-6);
}

.nzp-intro__frames {
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  gap: var(--space-4);
  height: 100%;
}

/* Icon left, copy right. */
.nzp-intro__frame {
  display: flex;
  align-items: flex-start;
  gap: var(--space-4);
  flex: 1;
  margin: 0;
  padding: var(--space-5);
  background: var(--color-bg);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-lg);
  box-shadow: 0 1px 2px rgba(6, 31, 17, 0.04);
  transition: border-color var(--transition), box-shadow var(--transition),
              transform var(--transition);
}
/* The spine is replaced by the icon; the earlier rule no longer applies. */
.nzp-intro__frame::before { content: none; }

.nzp-intro__icon {
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 46px;
  height: 46px;
  border-radius: 50%;
  background: var(--color-bg-alt);
  border: 1px solid var(--color-border);
  color: var(--color-primary);
}
.nzp-intro__icon svg { width: 24px; height: 24px; }

.nzp-intro__text {
  margin: 0;
  align-self: center;
  font-size: var(--fs-base);
  line-height: 1.65;
  color: var(--color-text-muted);
  text-align: left;
}
.nzp-text-media .nzp-intro__text { text-align: left; }

/* The opening statement: larger, but no longer set bold. */
.nzp-intro__frame--lead { background: var(--color-bg-alt); }
.nzp-intro__frame--lead .nzp-intro__icon {
  background: var(--color-primary);
  border-color: var(--color-primary);
  color: var(--color-text-invert);
}
/*
 * Larger and in the full-strength text colour, but the same face and weight as
 * the two cards below it. The display face at 400 still reads as bold beside
 * Inter, which is what made this look emphasised when it should not be.
 */
.nzp-intro__frame--lead .nzp-intro__text {
  /* Set explicitly: the card itself still carries the display face from an
     earlier round, and the text would otherwise inherit it. */
  font-family: var(--font-sans);
  font-size: var(--fs-md);
  font-weight: 400;
  line-height: 1.6;
  color: var(--color-text);
}

.nzp-intro__frame:hover {
  border-color: var(--color-secondary);
  box-shadow: 0 10px 26px rgba(6, 31, 17, 0.10);
  transform: translateY(-2px);
}

.nzp-intro__text a {
  color: var(--color-text);
  font-weight: 600;
  text-decoration: underline;
  text-decoration-color: var(--color-secondary);
  text-decoration-thickness: 2px;
  text-underline-offset: 3px;
}
.nzp-intro__text a:hover,
.nzp-intro__text a:focus-visible { text-decoration-color: var(--color-primary); }

/*
 * The photography column fills the height the copy sets. The slide width comes
 * from the aspect ratio rather than being fixed, which is what makes the strip
 * grow with the panel instead of leaving a gap beneath it.
 */
@media (min-width: 769px) {
  .nzp-intro .nzp-slideshow--panel { height: 100%; }
  .nzp-intro .nzp-slideshow--panel .nzp-slideshow__track { height: 100%; }
  .nzp-intro .nzp-slideshow--panel .nzp-slideshow__item {
    flex: 0 0 auto;
    width: auto;
    height: 100%;
    aspect-ratio: 4 / 3;
  }
}


/* --------------------------------------------------------------------------
   2. ASSET MANAGEMENT, ON ABOUT US
   It now follows a dark video header, and two dark full-bleed bands meeting
   edge to edge read as one long block with a seam in it. The section ground
   becomes the page's own grey and the photograph is inset into it, so the
   header ends cleanly and the section reads as a panel rather than a band.
   -------------------------------------------------------------------------- */
@media (min-width: 1024px) {
  .nzp-am {
    background: var(--color-bg-alt);
    padding-top: var(--space-8);
    padding-bottom: var(--space-8);
  }

  /*
   * Wide enough that the content container always sits inside the photograph.
   * Below 1024px it goes back to full bleed, because there the container's own
   * margin is too small to keep the copy off the edge of the image.
   */
  .nzp-am__bg,
  .nzp-am::before {
    left: 50%;
    right: auto;
    /* Inset vertically too, so grey shows above and below and the panel does
       not butt straight into the dark header above it. The section's own
       padding is larger than this, so the copy still sits inside the image. */
    top: var(--space-5);
    bottom: var(--space-5);
    transform: translateX(-50%);
    width: min(100% - var(--space-6), calc(var(--container-max) + var(--space-8) * 2));
    border-radius: var(--radius-lg);
  }
  .nzp-am__bg { overflow: hidden; }
}


/* --------------------------------------------------------------------------
   3. TRACK RECORD CHARTS
   -------------------------------------------------------------------------- */
/*
 * The panels become white cards on the section's own ground, so the title bar
 * inside them can be the dark element rather than another near-white box on
 * near-white. A white outline on a white panel was the problem.
 */
/*
 * margin: 0 matters. These panels are <figure>, and a browser's default
 * stylesheet gives figure `margin: 1em 40px`. That held each panel 40px inside
 * the slot it sits in, which is what left the energy traces ending in mid-air:
 * they anchor to the slot edge, and the panel edge was 40px further in.
 */
.nzp-vchart-panel {
  margin: 0;
  background: var(--color-bg);
  border: 1px solid var(--color-border);
  box-shadow: 0 2px 10px rgba(6, 31, 17, 0.05);
}
.nzp-section--alt .nzp-vchart-panel { background: var(--color-bg); }

/* The title now reads as a header on the card, in brand green. */
.nzp-vchart-panel .nzp-case-head,
.nzp-section--alt .nzp-vchart-panel .nzp-case-head {
  margin: calc(var(--space-4) * -1) calc(var(--space-2) * -1) var(--space-6);
  padding: var(--space-4) var(--space-5);
  background: linear-gradient(135deg, #0E3520 0%, var(--color-primary) 100%);
  border: 0;
  border-radius: var(--radius);
  box-shadow: 0 2px 8px rgba(6, 31, 17, 0.18);
}
.nzp-vchart-panel .nzp-case-head h3 {
  margin: 0;
  color: var(--color-text-invert);
}

/* Hovering a card lights its outline green and brightens the trace beside it. */
.nzp-vchart-panel:hover,
.nzp-vchart-panel:focus-within {
  border-color: var(--color-green-accent);
  box-shadow: 0 0 0 1px var(--color-green-accent),
              0 14px 34px rgba(47, 122, 75, 0.22);
  transform: translateY(-4px) scale(1.008);
}

/* Bars carry their colour inline, so only the shape belongs here. */
.nzp-vchart__bar {
  border-radius: 4px 4px 0 0;
  box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.14);
}


/* --- The discharge between the cards -------------------------------------- */
.nzp-spark--right {
  top: 50%;
  left: 100%;
  width: var(--space-8);
  height: 44px;
  transform: translateY(-50%);
}
.nzp-spark--down {
  left: 50%;
  top: 100%;
  width: 44px;
  height: var(--space-7);
  transform: translateX(-50%);
}

.nzp-spark__glow {
  stroke-width: 9;
  stroke-linecap: round;
  stroke-linejoin: round;
  opacity: 0.16;
}
.nzp-spark__core {
  stroke-width: 2.2;
  stroke-linecap: round;
  stroke-linejoin: round;
}
/* A short amber charge running the length of the conductor. */
.nzp-spark__charge {
  stroke-width: 2.6;
  stroke-linecap: round;
  stroke-linejoin: round;
  stroke-dasharray: 5 55;
  animation: nzp-spark-run 1.9s linear infinite;
  filter: drop-shadow(0 0 3px rgba(242, 193, 78, 0.9));
}
@keyframes nzp-spark-run {
  from { stroke-dashoffset: 60; }
  to   { stroke-dashoffset: 0; }
}
.nzp-spark__bolt { filter: drop-shadow(0 0 4px rgba(255, 215, 107, 0.95)); }

/* Terminals sit on the card edges, so the wire reads as plugged into both. */
.nzp-spark__node {
  fill: var(--color-green-accent);
  stroke: #FFFFFF;
  stroke-width: 1.5;
}

/* The trace answers the card it is attached to. */
.nzp-excellence__slot:hover .nzp-spark__core { stroke-width: 3; }
.nzp-excellence__slot:hover .nzp-spark__glow { opacity: 0.3; }

@media (prefers-reduced-motion: reduce) {
  .nzp-spark__charge { animation: none; opacity: 0; }
  .nzp-spark__bolt { display: none; }
}


@media (max-width: 768px) {
  .nzp-intro__frame { padding: var(--space-4); gap: var(--space-3); }
  .nzp-intro__icon { width: 38px; height: 38px; }
  .nzp-intro__icon svg { width: 20px; height: 20px; }
  .nzp-intro__frame--lead .nzp-intro__text { font-size: var(--fs-base); }
  .nzp-vchart-panel .nzp-case-head,
  .nzp-section--alt .nzp-vchart-panel .nzp-case-head { padding: var(--space-3) var(--space-4); }
}


/* ==========================================================================
   ROUND FOURTEEN
   ========================================================================== */

/* --------------------------------------------------------------------------
   1. HOMEPAGE INTRODUCTION
   All three cards now carry one treatment. The first used to be set apart by
   colour, size and face, which read as emphasis nobody asked for.
   -------------------------------------------------------------------------- */
.nzp-intro__frame,
.nzp-intro__frame--lead {
  align-items: center;
  gap: var(--space-5);
  padding: var(--space-5) var(--space-6);
  background: var(--color-bg-alt);
  border: 1px solid var(--color-border);
}

/*
 * All three at body size. The lead was 18px; matching the other two up to it
 * made the copy column taller than a 5:4 photograph beside it can ever be,
 * and the frame then had to overflow the container to keep its ratio. Coming
 * down to 16px is what lets uniform cards, a 5:4 frame and level tops and
 * bottoms all hold at once.
 */
.nzp-intro__text,
.nzp-intro__frame--lead .nzp-intro__text {
  font-family: var(--font-sans);
  font-size: var(--fs-base);
  font-weight: 400;
  line-height: 1.6;
  color: var(--color-text);
}

/* Bigger, and the same filled badge on every card. */
.nzp-intro__icon,
.nzp-intro__frame--lead .nzp-intro__icon {
  width: 60px;
  height: 60px;
  background: var(--color-primary);
  border: 0;
  color: var(--color-text-invert);
}
.nzp-intro__icon svg {
  width: 30px;
  height: 30px;
  /* The glyphs are drawn on a 24 unit grid and centre on it, so nothing here
     nudges them: the flex centring on the badge is enough. */
  display: block;
}

/*
 * The photograph frame is 5 wide by 4 high. The column split below is what
 * makes that hold: the frame's own height then comes out slightly taller than
 * the copy needs, and the cards - which are flex children - stretch to meet
 * it, so both sides still finish level.
 */
@media (min-width: 769px) {
  .nzp-intro .nzp-text-media {
    grid-template-columns: minmax(0, 0.82fr) minmax(0, 1fr);
  }
  /*
   * align-self: start matters. Stretched, the wrapper's height is definite and
   * aspect-ratio then derives the WIDTH from it - which came out wider than the
   * grid track and pushed the whole page 52px sideways. Unstretched, the width
   * comes from the track and the height follows, which is the way round this
   * needs to work. The copy column then stretches to meet it.
   */
  .nzp-intro__media {
    align-self: start;
    aspect-ratio: 5 / 4;
  }
  .nzp-intro .nzp-slideshow--panel .nzp-slideshow__item { aspect-ratio: 5 / 4; }
}


/* --------------------------------------------------------------------------
   2. TRACK RECORD CHARTS
   -------------------------------------------------------------------------- */
/*
 * The title was a solid brand-green slab, which at this size was far heavier
 * than anything else on the page. It becomes a quiet tinted bar with a green
 * spine instead: still clearly a header, no longer the loudest thing there.
 */
.nzp-vchart-panel .nzp-case-head,
.nzp-section--alt .nzp-vchart-panel .nzp-case-head {
  margin: calc(var(--space-4) * -1) calc(var(--space-2) * -1) var(--space-6);
  padding: var(--space-4) var(--space-5);
  background: var(--color-bg-alt);
  border: 1px solid var(--color-border);
  border-left: 3px solid var(--color-green-accent);
  border-radius: var(--radius);
  box-shadow: none;
  transition: background var(--transition), border-color var(--transition);
}
.nzp-vchart-panel .nzp-case-head h3 {
  margin: 0;
  color: var(--color-primary);
}

/*
 * Hover has to be unmistakable, so it is four things at once: a green ring,
 * a green bloom around the card, a lift, and the title bar warming to green.
 * The previous version changed only the border colour, which on a white card
 * against a white section was almost invisible.
 */
.nzp-vchart-panel,
.nzp-vchart-panel .nzp-case-head { transition-duration: 220ms; }

.nzp-vchart-panel:hover,
.nzp-vchart-panel:focus-within {
  border-color: #3FA164;
  background: #FBFEFC;
  /* Ring, halo, bloom, then the drop shadow that carries the lift. Four
     layers, because a single border change on a white card against a white
     section is invisible from a metre away. */
  box-shadow: 0 0 0 2px #3FA164,
              0 0 0 7px rgba(63, 161, 100, 0.20),
              0 0 46px rgba(47, 122, 75, 0.45),
              0 20px 46px rgba(6, 31, 17, 0.18);
  transform: translateY(-6px);
}
.nzp-vchart-panel:hover .nzp-case-head,
.nzp-vchart-panel:focus-within .nzp-case-head {
  background: #D9EDE1;
  border-color: #A8D3BB;
  border-left-width: 5px;
  border-left-color: #3FA164;
}
/* The bars warm up with it. */
.nzp-vchart-panel:hover .nzp-vchart__bar,
.nzp-vchart-panel:focus-within .nzp-vchart__bar {
  filter: saturate(1.2) brightness(1.06);
}

@media (prefers-reduced-motion: reduce) {
  .nzp-vchart-panel:hover,
  .nzp-vchart-panel:focus-within { transform: none; }
}


@media (max-width: 768px) {
  .nzp-intro__frame,
  .nzp-intro__frame--lead { padding: var(--space-4); gap: var(--space-4); }
  .nzp-intro__icon,
  .nzp-intro__frame--lead .nzp-intro__icon { width: 46px; height: 46px; }
  .nzp-intro__icon svg { width: 24px; height: 24px; }
  .nzp-intro__text,
  .nzp-intro__frame--lead .nzp-intro__text { font-size: var(--fs-base); }
}


/* ==========================================================================
   ROUND FIFTEEN
   ========================================================================== */

/* --- 9. Press enquiries: the email really is centred -------------------- */
.nzp-container--narrow > p.nzp-press-contact {
  text-align: center;
  text-justify: auto;
}


/* --- 10. The dark wedges under the sand rules --------------------------- */
/*
 * Each slide carries `border-right: 3px solid` in the brand sand, and the base
 * .nzp-slideshow__item has a 4px border-radius. The radius clipped the bottom
 * of that sand rule, and the panel's own dark-green background showed through
 * the clipped corner as a small near-black triangle.
 *
 * Square corners inside the panel: the panel already rounds its own outer
 * edge, so the individual frames never needed a radius of their own.
 */
.nzp-slideshow--panel .nzp-slideshow__item { border-radius: 0; }

/*
 * And the background goes to the grey the placeholder already uses. Nothing
 * should show between frames, but if a slide is still decoding, a light grey
 * gap reads as a loading image rather than as a black slab.
 */
.nzp-slideshow--panel { background: var(--color-light-dark); }


/* --- 11. Intro icons: larger, and responsive to scroll on a phone ------- */
.nzp-intro__icon,
.nzp-intro__frame--lead .nzp-intro__icon {
  width: 68px;
  height: 68px;
}
.nzp-intro__icon svg { width: 34px; height: 34px; }

/*
 * A phone has no hover, so the card that is currently under the reader's eye
 * lights up instead. js/navigation.js sets .is-active on the card nearest the
 * middle of the screen; these are the same declarations as :hover so the two
 * behave identically.
 */
@media (max-width: 768px) {
  .nzp-intro__icon,
  .nzp-intro__frame--lead .nzp-intro__icon { width: 56px; height: 56px; }
  .nzp-intro__icon svg { width: 28px; height: 28px; }

  .nzp-intro__frame.is-active {
    border-color: var(--color-secondary);
    box-shadow: 0 10px 26px rgba(6, 31, 17, 0.10);
    transform: translateY(-2px);
  }
  .nzp-intro__frame.is-active .nzp-intro__icon { transform: scale(1.08); }
  .nzp-intro__icon { transition: transform var(--transition); }
}

@media (prefers-reduced-motion: reduce) {
  .nzp-intro__frame.is-active { transform: none; }
  .nzp-intro__frame.is-active .nzp-intro__icon { transform: none; }
}


/* --- 12. Asset Management: cover more, and lift the green --------------- */
@media (min-width: 1024px) {
  /*
   * Close to full width now, with only a thin margin of page grey left down
   * each side, and a shallower gap above and below. The content container is
   * still comfortably inside the photograph at every width this applies at.
   */
  .nzp-am__bg,
  .nzp-am::before {
    top: var(--space-3);
    bottom: var(--space-3);
    width: calc(100% - var(--space-5));
  }
  .nzp-am {
    padding-top: var(--space-7);
    padding-bottom: var(--space-7);
  }
}

/*
 * The scrim was 0.82 to 0.88 of the brand green, which buried the photograph.
 * Lifted so the office underneath reads, while keeping enough density behind
 * white text - measured on the rendered page rather than judged by eye.
 */
.nzp-am::before {
  background: linear-gradient(rgba(6, 31, 17, 0.66), rgba(6, 31, 17, 0.74));
}


/* ==========================================================================
   ROUND SIXTEEN
   ========================================================================== */

/* --- 1. Latest News becomes a scroller ---------------------------------- */
/*
 * It reuses .nzp-doc-shell / -slider / -track, so js/carousel.js drives it
 * with no extra wiring. Only the card needs sizing: a press card was built for
 * a grid cell, and as a flex child it has to be told how wide to be.
 */
.nzp-news-shell .nzp-press-card--slide {
  flex: 1 0 clamp(240px, 26vw, 316px);
  display: flex;
  flex-direction: column;
  min-width: 0;
}
.nzp-news-shell .nzp-press-card--slide .nzp-press-card__body {
  display: flex;
  flex-direction: column;
  flex: 1;
}
/* The "Read more" line sits on the bottom edge whatever the headline length. */
.nzp-news-shell .nzp-press-card--slide .nzp-link-arrow { margin-top: auto; }


/* --- 2. Three document cards now fit without clipping ------------------- */
/*
 * The arrow gutter was 72px a side, which left the slider 980px - and three
 * 330px cards plus their gaps need 1038px, so the third was cut by 60px with
 * empty container either side of it.
 *
 * 56px is still wider than the 48px arrow plus its 6px offset, so the arrows
 * stay clear of the cards, and the card cap comes down just enough that three
 * fit whole: 3 x 326 + 2 x 24 = 1026 inside 1036.
 */
@media (min-width: 769px) {
  .nzp-doc-shell.has-overflow {
    padding-left: 56px;
    padding-right: 56px;
  }
}
/*
 * 316px, not 326: the slider measures 1012px inside the 56px gutters, and
 * three cards plus their two 24px gaps have to fit inside that -
 * 3 x 316 + 48 = 996, which clears with 16px to spare. At 326 the third card
 * was still being clipped by 16px.
 */
.nzp-doc { flex-basis: clamp(240px, 26vw, 316px); }


/* --- 3. Asset Management back to a full-bleed photograph ---------------- */
/*
 * Reverts the inset panel. It now sits below Key Facts rather than directly
 * under the dark video header, so it no longer needs a grey margin to stop two
 * dark bands running together - the tinted Key Facts band does that job.
 *
 * The lighter scrim from the previous round stays; only the framing changes.
 */
@media (min-width: 1024px) {
  .nzp-am {
    padding-top: var(--space-8);
    padding-bottom: var(--space-8);
  }
  .nzp-am__bg,
  .nzp-am::before {
    top: 0;
    bottom: 0;
    left: 0;
    right: 0;
    width: auto;
    transform: none;
    border-radius: 0;
  }
}

/* Slides share the tallest card's height, so their lower edges line up. */
.nzp-news-shell .nzp-doc-track { align-items: stretch; }
.nzp-news-shell .nzp-press-card--slide { height: auto; }

/* ==========================================================================
   ROUND SEVENTEEN
   ========================================================================== */

/* --- 1. Slides fill the track exactly, so the ends sit level ------------- */
/*
 * Three cards and their two gaps now add up to exactly the visible width, so
 * there is no leftover slack to fall on one side. Previously the cards were a
 * fixed 316px and the remainder - about 12px - all landed on the right, which
 * is why the first card sat closer to its arrow than the last did to its own.
 *
 * A percentage basis is safe here only because .nzp-doc-track is width:100%.
 * Against a max-content track it would resolve against the whole strip and
 * collapse everything into one enormous slide.
 */
@media (min-width: 769px) {
  .nzp-doc,
  .nzp-news-shell .nzp-press-card--slide {
    flex: 0 0 calc((100% - 2 * var(--space-5)) / 3);
  }
}


/* --- 3. Asset Management on a phone: stop the extreme crop -------------- */
/*
 * `cover` on a section that is ~390px wide and well over 1000px tall scales a
 * 16:9 photograph until its HEIGHT fills, which blows the width up to roughly
 * three times the screen. The result was a meaningless close-up.
 *
 * Fitting to the width instead shows the photograph at something close to its
 * real proportions. Each image then anchors to the end of the section it
 * belongs to: image A to the top, behind the first card, and image B to the
 * bottom, behind the second - which is the order they are read in.
 */
@media (max-width: 768px) {
  .nzp-am__bg {
    background-size: 100% auto;
    background-repeat: no-repeat;
  }
  .nzp-am__bg--a { background-position: center top; }
  .nzp-am__bg--b { background-position: center bottom; }
}


/* --- 4a. Hover states are for devices that can hover -------------------- */
/*
 * On a touch screen :hover sticks after a tap and will not clear until you
 * tap elsewhere, so tapping a chart left its title bar stuck in the lit
 * state. :focus-within did the same, because tapping focuses the card.
 *
 * The lit state moves behind a hover query, and phones get .is-active from
 * the scroll observer instead - the same look, driven by what you are
 * actually looking at.
 */
@media (hover: hover) {
  .nzp-vchart-panel:hover,
  .nzp-vchart-panel:focus-visible {
    border-color: #3FA164;
    background: #FBFEFC;
    box-shadow: 0 0 0 2px #3FA164,
                0 0 0 7px rgba(63, 161, 100, 0.20),
                0 0 46px rgba(47, 122, 75, 0.45),
                0 20px 46px rgba(6, 31, 17, 0.18);
    transform: translateY(-6px);
  }
  .nzp-vchart-panel:hover .nzp-case-head,
  .nzp-vchart-panel:focus-visible .nzp-case-head {
    background: #D9EDE1;
    border-color: #A8D3BB;
    border-left-width: 5px;
    border-left-color: #3FA164;
  }
  .nzp-vchart-panel:hover .nzp-vchart__bar,
  .nzp-vchart-panel:focus-visible .nzp-vchart__bar {
    filter: saturate(1.2) brightness(1.06);
  }
}

/* Cancel the older rules that fire on touch. */
@media (hover: none) {
  .nzp-vchart-panel:hover,
  .nzp-vchart-panel:focus-within {
    border-color: var(--color-border);
    background: var(--color-bg);
    box-shadow: 0 2px 10px rgba(6, 31, 17, 0.05);
    transform: none;
  }
  .nzp-vchart-panel:hover .nzp-case-head,
  .nzp-vchart-panel:focus-within .nzp-case-head {
    background: var(--color-bg-alt);
    border-color: var(--color-border);
    border-left-width: 3px;
    border-left-color: var(--color-green-accent);
  }
  .nzp-vchart-panel:hover .nzp-vchart__bar,
  .nzp-vchart-panel:focus-within .nzp-vchart__bar { filter: none; }
}

/* The scroll-driven equivalent, used on phones. */
.nzp-vchart-panel.is-active {
  border-color: #3FA164;
  background: #FBFEFC;
  box-shadow: 0 0 0 2px #3FA164,
              0 0 0 7px rgba(63, 161, 100, 0.20),
              0 0 34px rgba(47, 122, 75, 0.38);
}
.nzp-vchart-panel.is-active .nzp-case-head {
  background: #D9EDE1;
  border-color: #A8D3BB;
  border-left-width: 5px;
  border-left-color: #3FA164;
}
.nzp-vchart-panel.is-active .nzp-vchart__bar { filter: saturate(1.2) brightness(1.06); }


/* --- 4b. The discharge, on a phone -------------------------------------- */
/*
 * The charts stack, so a trace running left to right has nothing to cross.
 * The horizontal ones are dropped and a vertical one links each card to the
 * next down the column, which is the order they are now read in.
 */
@media (max-width: 768px) {
  .nzp-spark { display: block; }
  .nzp-spark--right { display: none; }

  .nzp-excellence__col { gap: var(--space-7); }
  .nzp-excellence { gap: var(--space-7); }

  .nzp-spark--down {
    left: 50%;
    top: 100%;
    width: 40px;
    height: var(--space-7);
    transform: translateX(-50%);
  }

  /* The last card in the column has nothing below it to link to. */
  .nzp-excellence__col:last-child .nzp-excellence__slot:last-child .nzp-spark--down { display: none; }

  /* The trace brightens with the card it belongs to. */
  .nzp-excellence__slot:has(.is-active) .nzp-spark__core { stroke-width: 3; }
  .nzp-excellence__slot:has(.is-active) .nzp-spark__glow { opacity: 0.32; }
}

/* On desktop the second slot links sideways, not down - the downward trace it
   now carries is there for the stacked phone column only. */
@media (min-width: 769px) {
  .nzp-excellence__col:first-child .nzp-excellence__slot:last-child .nzp-spark--down { display: none; }
}
/* The still behind the animated mark. See the note in header.php: the clip
   opens on nearly a second of near-empty frames, so without this the logo
   disappeared for that second on every fresh load. */
.nzp-logo-animation {
  background-image: var(--nzp-logo-still, none);
  background-size: contain;
  background-position: center;
  background-repeat: no-repeat;
}

/* ==========================================================================
   ROUND EIGHTEEN
   ========================================================================== */

/* --- 2. "View all coverage" sits under the articles --------------------- */
/*
 * The container becomes a flex column purely so the link can be ordered. It
 * reads the same way at every width: the heading, then the coverage itself,
 * then the link through to the rest of it.
 */
.nzp-news-container {
  display: flex;
  flex-direction: column;
}
.nzp-news-more {
  order: 3;
  margin: var(--space-6) 0 0;
  text-align: center;
}
.nzp-news-container > .nzp-section-head { order: 1; }
.nzp-news-container > .nzp-grid { order: 2; }


/* --- 3. Asset Management: each photograph fills the part you can see ---- */
/*
 * Fitting the whole photograph to the width left most of the section empty;
 * filling the whole section cropped it about six times over. Neither is what
 * is wanted.
 *
 * Instead each image covers only the band it belongs to - image A the heading
 * and the first card, image B the second - so `cover` is working against a box
 * roughly half the height, which is a far gentler crop, and the area a reader
 * is actually looking at is filled.
 *
 * The two bands overlap slightly so the crossfade never reveals a seam.
 */
@media (max-width: 768px) {
  .nzp-am__bg {
    background-size: cover;
    background-repeat: no-repeat;
  }
  .nzp-am__bg--a {
    top: 0;
    bottom: 40%;
    background-position: center top;
  }
  .nzp-am__bg--b {
    top: 55%;
    bottom: 0;
    background-position: center bottom;
  }
}

/* ==========================================================================
   ROUND NINETEEN
   ========================================================================== */

/*
 * On a phone both photographs stay up, each holding its own band.
 *
 * The crossfade is a hover effect: one image fades out as the other fades in.
 * Scrolling between the two cards therefore passed through a moment where
 * neither was at full opacity and the section showed as flat green. There is
 * no pointer here to fade anything for, so both simply stay - image A behind
 * the heading and the first card, image B behind the second - and the section
 * is covered end to end at every scroll position.
 */
@media (max-width: 768px) {
  .nzp-am__bg--a,
  .nzp-am__bg--b,
  .nzp-am.is-hovered .nzp-am__bg--a,
  .nzp-am.is-hovered .nzp-am__bg--b {
    opacity: 1;
    transition: none;
  }

  /* The bands meet with a small overlap so no seam shows between them. */
  .nzp-am__bg--a { top: 0; bottom: 40%; }
  .nzp-am__bg--b { top: 58%; bottom: 0; }
}
/*
 * The seam sits at --nzp-am-split, which js/navigation.js measures as the
 * midpoint of the gap between the two cards. Each image runs 12px past it so
 * they overlap inside that gap and no green line can show between them.
 *
 * The percentages are the fallback if the script has not run yet; they are
 * close to the measured position at a typical phone width.
 */
@media (max-width: 768px) {
  .nzp-am__bg--a {
    top: 0;
    bottom: auto;
    height: calc(var(--nzp-am-split, 61%) + 12px);
  }
  .nzp-am__bg--b {
    top: calc(var(--nzp-am-split, 60%) - 12px);
    bottom: 0;
  }
}