/* ===========================================================
   Perfex Insight — shared production design system

   AUTHORITATIVE OWNER of every shared public primitive: tokens,
   typography, focus, buttons, badges, screenshots, cards, tables,
   callouts, navigation, dark surfaces and the responsive scale.

   Loaded by BOTH public surfaces:
     landingpage/index.php   + assets/home.css      (page layer)
     landingpage/addons/     + assets/catalogue.css (page layer)

   A page layer may add layout for its own sections. It must never
   redefine a token, a button, a card or a focus ring — those live
   here and only here.

   GENERATED from _design-system/{tokens,system}.css — do not hand-edit.
   Regenerate with: php landingpage/_src/build-css.php
   =========================================================== */

:root {
  /* ---- Brand, kept verbatim from the existing identity ---- */
  --pi-navy: #0a0f1e; /* dark sections, footer */
  --pi-navy-2: #0f1729; /* dark section step */
  --pi-ink: #111c2e; /* headings — 17.08:1 on white */
  --pi-blue: #2563eb; /* primary action — 5.17:1 on white */

  /* ---- Semantic surface + text ---- */
  --color-bg: #ffffff;
  --color-surface: #ffffff;
  --color-surface-soft: #f5f8fc; /* kept: existing --soft */
  --color-surface-inverse: var(--pi-navy);

  --color-text: var(--pi-ink);
  --color-text-muted: #5a6b82; /* kept: 5.44:1 on white */
  --color-text-subtle: #667387; /* was #7c8aa0 (3.50:1). 4.81:1 on white,
     and 4.51:1 on --color-surface-soft, where .pi-eyebrow sits. #68758a
     cleared white at 4.67:1 but measured only 4.38:1 on the soft ground. */
  --color-text-inverse: #ffffff;
  --color-text-inverse-muted: #b3c0d4; /* 9.34:1 on navy */

  --color-border: #e6edf5; /* kept: existing --line */
  --color-border-strong: #cfdcea;
  --color-border-inverse: rgba(255, 255, 255, 0.18);

  /* ---- Action ---- */
  --color-primary: var(--pi-blue);
  --color-primary-hover: #1d4ed8; /* kept: existing --blue-2 */
  --color-primary-active: #1a43b8;
  --color-on-primary: #ffffff; /* 5.17:1 / 6.31:1 on hover */

  /* ---- Semantic status. Darkened for text use. ---- */
  --color-success: #0f7a3d; /* was #16a34a (3.30:1) -> 4.72:1 */
  --color-success-soft: #e7f4ec;
  /* #f59e0b measures 2.15:1 as TEXT on white, so it was never safe for a
     warning label. (The old .btn-buy was not the failure: it paired amber with
     #2a1a02 text at 7.84:1. The real CTA failure was .btn-primary — white on
     its gradient's cyan midpoint #06b6d4 is 2.43:1.) */
  --color-warning: #9a5700; /* 5.34:1 as text on white */
  --color-warning-soft: #fdf1e3;
  --color-danger: #b42318;
  --color-danger-soft: #fdecea;
  --color-info: #1d4ed8;
  --color-info-soft: #e8eefc;

  /* ---- Dark ecosystem band ----
     One accent per BUSINESS GROUP, not per product: thirteen colours would
     read as thirteen brands. Every accent is measured against the tile it sits
     on (#111a2e), not just against the navy ground, because that is where the
     "Explore" label actually renders:
       finance 7.15:1 · assets 9.22:1 · operations 9.25:1 · property 7.62:1
     The soft variants are the icon plates. They are flat colours rather than
     color-mix() so the band does not depend on a newer CSS feature. */
  --accent-finance: #7aa5ff;
  --accent-assets: #5ecfc0;
  --accent-operations: #e8b473;
  --accent-property: #b79dfb;

  /* icon plates: the accent at 18% over the tile, resolved to a flat colour */
  --accent-finance-soft: #243354;
  --accent-assets-soft: #1f3b48;
  --accent-operations-soft: #38363a;
  --accent-property-soft: #2f3253;

  --color-eco-tile: #111a2e;
  --color-eco-tile-hover: #16203a;
  --color-eco-eyebrow: #b3c0d4;

  /* Problem/solution story. Warm neutral, NOT red: the point is "this is the
     state you are in today", not "this is an error". */
  /* Icon container on the dark band: a flat fill and a flat line per family.
     Computed solid values, never rgba over the band, so the tile can sit on
     either eco surface without the tint shifting. */
  --accent-finance-fill: #1b2a4a;
  --accent-finance-line: #33507f;
  --accent-assets-fill: #14313c;
  --accent-assets-line: #2b5c68;
  --accent-operations-fill: #332c26;
  --accent-operations-line: #5f4e3a;
  --accent-property-fill: #262444;
  --accent-property-line: #45407a;
  /* Brand palette, quoted from brand/README.md so the wordmark and the
     inlined icon cannot drift apart. */
  /* Hero ground. Both deliberately near-invisible: the grid line is 4% ink
     and the wash is a 6% brand tint. Measured, not eyeballed. */
  --color-eco-tile-line: #1d2740;
  --color-eco-req-edge: #33507f;
  --hero-grid-line: rgba(23, 32, 51, 0.035);
  --hero-wash: rgba(59, 130, 246, 0.07);
  --color-brand-ink: #172033;
  --color-brand-signal: #3b82f6;
  --color-story-problem: #faf8f4;
  --color-story-problem-edge: #c9a227;
  --color-story-problem-text: #7a5c12;

  /* ---- Focus. One ring, legible on both grounds. ---- */
  --color-focus: #1d4ed8;
  --color-focus-inverse: #9dc0ff;
  --focus-width: 3px;
  --focus-offset: 2px;

  /* ---- Spacing: one 4px-based scale ---- */
  --space-1: 4px;
  --space-2: 8px;
  --space-3: 12px;
  --space-4: 16px;
  --space-5: 24px;
  --space-6: 32px;
  --space-7: 48px;
  --space-8: 64px;
  --space-9: 96px;

  /* ---- Radius: three roles, replacing twelve ad-hoc values ---- */
  --radius-control: 6px;
  --radius-panel: 10px;
  --radius-media: 14px;
  --radius-pill: 999px; /* kept: badges/chips only */

  /* ---- Depth: two treatments only ---- */
  --shadow-resting: 0 1px 2px rgba(15, 23, 42, 0.06);
  --shadow-media: 0 12px 32px rgba(10, 15, 30, 0.14);

  /* ---- Type ----
     Decision: deliberate system stack. The old stack named "Inter"
     first and never loaded it, so the page already renders in the
     system face. Loading a webfont would add a third-party request,
     render delay and a privacy consideration for zero legibility gain. */
  --font-sans:
    system-ui, -apple-system, "Segoe UI Variable Text", "Segoe UI", Roboto,
    "Helvetica Neue", Arial, sans-serif;
  --font-mono:
    ui-monospace, "Cascadia Mono", "Segoe UI Mono", "SF Mono", Menlo, Consolas,
    "Liberation Mono", monospace;

  /* 1.25 modular scale, 16px base */
  --text-xs: 0.75rem; /* 12 */
  --text-sm: 0.875rem; /* 14 */
  --text-base: 1rem; /* 16 */
  --text-lg: 1.25rem; /* 20 */
  --text-xl: 1.5625rem; /* 25 */
  --text-2xl: 1.9375rem; /* 31 */
  --text-3xl: 2.4375rem; /* 39 */
  --text-4xl: 3.0625rem; /* 49 — hero ceiling */

  --weight-regular: 400;
  --weight-medium: 500;
  --weight-semibold: 600;
  /* Display only. The stack is system-ui, so 700 is a real face on every
     target OS and costs nothing to download — no synthesised bolding. */
  --weight-bold: 700;

  --leading-tight: 1.15;
  --leading-heading: 1.25;
  --leading-body: 1.6;
  --measure: 68ch;

  /* ---- Layout ---- */
  --container: 1200px;
  --container-narrow: 760px;
}

/* ---------------- base ---------------- */

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

body {
  margin: 0;
  background: var(--color-bg);
  color: var(--color-text);
  font-family: var(--font-sans);
  font-size: var(--text-base);
  line-height: var(--leading-body);
  -webkit-font-smoothing: antialiased;
}

h1,
h2,
h3,
h4 {
  margin: 0 0 var(--space-3);
  color: var(--color-text);
  font-weight: var(--weight-semibold);
  line-height: var(--leading-heading);
  letter-spacing: -0.015em;
  text-wrap: balance;
}

h1 {
  font-size: clamp(var(--text-2xl), 4.2vw, var(--text-4xl));
  line-height: var(--leading-tight);
  letter-spacing: -0.022em;
}
h2 {
  font-size: clamp(var(--text-xl), 3vw, var(--text-3xl));
}
h3 {
  font-size: var(--text-lg);
}
h4 {
  font-size: var(--text-base);
}

p {
  margin: 0 0 var(--space-4);
  max-width: var(--measure);
  color: var(--color-text-muted);
}

a {
  color: var(--color-primary);
  text-decoration: none;
}
a:hover {
  text-decoration: underline;
}

/* Numerals line up wherever they are compared. */
.pi-num,
td.pi-num,
th.pi-num {
  font-variant-numeric: tabular-nums;
}

/* ---------------- focus ----------------
   One visible ring everywhere, on both grounds. Native outline is
   replaced, never removed. */

:where(a, button, input, select, textarea, summary, [tabindex]):focus-visible {
  outline: var(--focus-width) solid var(--color-focus);
  outline-offset: var(--focus-offset);
  border-radius: var(--radius-control);
}

.pi-on-dark :where(a, button, input, select, summary, [tabindex]):focus-visible {
  outline-color: var(--color-focus-inverse);
}

/* ---------------- buttons ----------------
   Exactly three levels. No per-section variants. */

.pi-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-2);
  min-height: 44px;
  padding: var(--space-3) var(--space-5);
  border: 1px solid transparent;
  border-radius: var(--radius-control);
  font: inherit;
  font-size: var(--text-sm);
  font-weight: var(--weight-semibold);
  line-height: 1.2;
  text-decoration: none;
  white-space: nowrap;
  cursor: pointer;
  transition:
    background-color 0.15s ease,
    border-color 0.15s ease,
    color 0.15s ease;
}
.pi-btn:hover {
  text-decoration: none;
}

.pi-btn--primary {
  background: var(--color-primary);
  border-color: var(--color-primary);
  color: var(--color-on-primary);
}
.pi-btn--primary:hover {
  background: var(--color-primary-hover);
  border-color: var(--color-primary-hover);
}
.pi-btn--primary:active {
  background: var(--color-primary-active);
  border-color: var(--color-primary-active);
}

.pi-btn--secondary {
  background: var(--color-surface);
  border-color: var(--color-border-strong);
  color: var(--color-text);
}
.pi-btn--secondary:hover {
  border-color: var(--color-primary);
  color: var(--color-primary);
}
.pi-btn--secondary:active {
  background: var(--color-surface-soft);
}

.pi-btn--quiet {
  min-height: 44px;
  padding: var(--space-2) 0;
  background: none;
  border-color: transparent;
  color: var(--color-primary);
}
.pi-btn--quiet:hover {
  color: var(--color-primary-hover);
  text-decoration: underline;
}
.pi-btn--quiet .pi-btn__arrow {
  transition: transform 0.15s ease;
}
.pi-btn--quiet:hover .pi-btn__arrow {
  transform: translateX(3px);
}

.pi-btn[aria-disabled="true"],
.pi-btn:disabled {
  background: var(--color-surface-soft);
  border-color: var(--color-border);
  color: var(--color-text-subtle);
  cursor: not-allowed;
}

.pi-on-dark .pi-btn--secondary {
  background: transparent;
  border-color: var(--color-border-inverse);
  color: var(--color-text-inverse);
}
.pi-on-dark .pi-btn--secondary:hover {
  border-color: #ffffff;
  color: #ffffff;
}
.pi-on-dark .pi-btn--quiet {
  color: var(--color-focus-inverse);
}


/* ---------------- screenshot / media ----------------
   The product UI is the visual. No browser chrome, no floating
   cards, no overlays. */

.pi-shot {
  display: block;
  margin: 0;
  border: 1px solid var(--color-border);
  border-radius: var(--radius-media);
  background: var(--color-surface-soft);
  overflow: hidden;
}
/* Descendant, not child: a <picture> wrapper would break `>` and leave the
   image at its intrinsic width, silently clipped by the overflow rule. */
.pi-shot img {
  display: block;
  width: 100%;
  height: auto;
}
.pi-shot--raised {
  border-color: var(--color-border-strong);
  box-shadow: var(--shadow-media);
}
.pi-shot__caption {
  padding: var(--space-2) var(--space-3);
  border-top: 1px solid var(--color-border);
  background: var(--color-surface);
  color: var(--color-text-subtle);
  font-size: var(--text-xs);
}

/* ---------------- badges / meta ---------------- */

.pi-badge {
  display: inline-flex;
  align-items: center;
  gap: var(--space-1);
  padding: 2px var(--space-2);
  border-radius: var(--radius-pill);
  font-size: var(--text-xs);
  font-weight: var(--weight-medium);
  line-height: 1.5;
  white-space: nowrap;
}
/* Marks an external destination inside a button label. Only rendered on the
   "Buy on CodeCanyon" branch, so it is absent from generated output until a
   product has a real marketplace_url — present in the template regardless. */
.pi-btn__ext {
  font-size: 0.85em;
  opacity: 0.85;
}

.pi-badge--requires {
  background: var(--color-info-soft);
  color: var(--color-info);
}
.pi-badge--live {
  background: var(--color-success-soft);
  color: var(--color-success);
}

.pi-meta {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-1) var(--space-4);
  margin: 0;
  padding: 0;
  list-style: none;
  font-size: var(--text-sm);
  color: var(--color-text-muted);
}
.pi-meta b {
  color: var(--color-text);
  font-weight: var(--weight-medium);
  font-variant-numeric: tabular-nums;
}

/* ---------------- product card ----------------
   Dense catalogue row, not a large marketing card. */

/* auto-FIT, not auto-fill: a group with fewer products than the row can hold
   collapses the unused tracks and fills its row, instead of leaving an empty
   card-sized hole. Combined with the wider page container /addons adopts above
   1600px, a four-product group completes one row while three-product groups
   stay flush. */
.pi-catalogue {
  display: grid;
  gap: var(--space-4);
  grid-template-columns: repeat(auto-fit, minmax(320px, 1fr));
}

.pi-card {
  display: grid;
  grid-template-rows: auto 1fr auto;
  border: 1px solid var(--color-border);
  border-radius: var(--radius-panel);
  background: var(--color-surface);
  overflow: hidden;
}
.pi-card:hover {
  border-color: var(--color-border-strong);
}
.pi-card__media {
  border-bottom: 1px solid var(--color-border);
  background: var(--color-surface-soft);
}
.pi-card__media img {
  display: block;
  width: 100%;
  height: auto;
}
/* The card is a 3-row grid (media / body / actions), so the body already
   stretches. Making it a column and letting the purpose take the slack lands
   the counts and the requirement badge on one line across a whole row, even
   when one product's purpose wraps to two lines and its neighbours' do not. */
.pi-card__body {
  display: flex;
  flex-direction: column;
  padding: var(--space-4);
}
.pi-card__purpose {
  flex: 1 0 auto;
}
.pi-card__head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--space-3);
  margin-bottom: var(--space-1);
}
.pi-card__name {
  margin: 0;
  font-size: var(--text-base);
  font-weight: var(--weight-semibold);
}
.pi-card__price {
  font-size: var(--text-lg);
  font-weight: var(--weight-semibold);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}
.pi-card__purpose {
  margin: 0 0 var(--space-3);
  font-size: var(--text-sm);
  color: var(--color-text-muted);
}
.pi-card__req {
  margin: var(--space-3) 0 0;
  padding-top: var(--space-3);
  border-top: 1px solid var(--color-border);
  font-size: var(--text-xs);
  color: var(--color-text-subtle);
}
.pi-card__actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-2);
  padding: var(--space-3) var(--space-4);
  border-top: 1px solid var(--color-border);
  background: var(--color-surface-soft);
}
.pi-card__actions .pi-btn {
  min-height: 40px;
  padding: var(--space-2) var(--space-4);
}
/* Marketplace-pending state. It sits on its own line BELOW the action row, not
   inline with the buttons, where a bare grey label read as a disabled third
   button. Matches .pi-status on the platform block: a clock glyph plus text,
   never a control. The glyph means the state does not rely on colour alone. */
.pi-card__status {
  flex: 1 0 100%;
  margin-top: var(--space-1);
  font-size: var(--text-xs);
  color: var(--color-text-muted);
}
.pi-card__status::before {
  content: "◷ ";
  color: var(--color-text-subtle);
}

/* Group heading for the four business areas. */
.pi-group {
  margin: 0 0 var(--space-4);
  padding-bottom: var(--space-2);
  border-bottom: 1px solid var(--color-border);
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--space-4);
}
.pi-group__name {
  margin: 0;
  font-size: var(--text-lg);
}
.pi-group__count {
  font-size: var(--text-sm);
  color: var(--color-text-subtle);
  font-variant-numeric: tabular-nums;
}

/* ---------------- tables ---------------- */

.pi-table-wrap {
  overflow-x: auto;
  border: 1px solid var(--color-border);
  border-radius: var(--radius-panel);
  background: var(--color-surface);
}
.pi-table {
  width: 100%;
  min-width: 520px;
  border-collapse: collapse;
  font-size: var(--text-sm);
}
/* Column headers only. A `th scope="row"` is a product name, not a label, so
   it must not inherit the uppercase/small treatment. */
.pi-table thead th {
  padding: var(--space-3) var(--space-4);
  border-bottom: 1px solid var(--color-border-strong);
  background: var(--color-surface-soft);
  color: var(--color-text-muted);
  font-size: var(--text-xs);
  font-weight: var(--weight-semibold);
  letter-spacing: 0.06em;
  text-transform: uppercase;
  text-align: left;
  white-space: nowrap;
}
.pi-table tbody th,
.pi-table tfoot th {
  padding: var(--space-3) var(--space-4);
  border-bottom: 1px solid var(--color-border);
  font-size: var(--text-sm);
  font-weight: var(--weight-medium);
  text-align: left;
  vertical-align: top;
}
.pi-table tfoot th,
.pi-table tfoot td {
  border-top: 1px solid var(--color-border-strong);
  border-bottom: 0;
  font-weight: var(--weight-semibold);
  background: var(--color-surface-soft);
}
.pi-table td {
  padding: var(--space-3) var(--space-4);
  border-bottom: 1px solid var(--color-border);
  vertical-align: top;
}
.pi-table tbody tr:last-child td {
  border-bottom: 0;
}
.pi-table th.pi-num,
.pi-table td.pi-num {
  text-align: right;
}
.pi-table__product {
  color: var(--color-text);
  font-weight: var(--weight-medium);
}
.pi-table tbody tr:hover td {
  background: var(--color-surface-soft);
}

/* ---------------- callouts: four only ---------------- */

.pi-callout {
  margin: 0 0 var(--space-4);
  padding: var(--space-4);
  border: 1px solid var(--color-border);
  border-left: 3px solid var(--color-border-strong);
  border-radius: var(--radius-control);
  background: var(--color-surface);
  max-width: var(--measure);
}
.pi-callout__label {
  display: block;
  margin-bottom: var(--space-1);
  font-size: var(--text-xs);
  font-weight: var(--weight-semibold);
  letter-spacing: 0.07em;
  text-transform: uppercase;
}
.pi-callout p {
  margin: 0;
  font-size: var(--text-sm);
}
.pi-callout--note {
  border-left-color: var(--color-info);
}
.pi-callout--note .pi-callout__label {
  color: var(--color-info);
}
.pi-callout--requirement {
  border-left-color: var(--color-text-muted);
}
.pi-callout--requirement .pi-callout__label {
  color: var(--color-text-muted);
}
.pi-callout--warning {
  border-left-color: var(--color-warning);
}
.pi-callout--warning .pi-callout__label {
  color: var(--color-warning);
}
.pi-callout--version {
  border-left-color: var(--color-success);
}
.pi-callout--version .pi-callout__label {
  color: var(--color-success);
}

/* ---------------- navigation ---------------- */

/* ===========================================================
   Header
   Shared by all fifteen public pages from four templates, so it
   lives here, not in a page layer. Brand markup comes from the
   single partial landingpage/_src/brand.php.
   =========================================================== */

.pi-nav {
  position: relative;
  display: flex;
  align-items: center;
  gap: var(--space-5);
  /* Block padding sets the bar height: 14px + 34px lockup + 14px = 62px,
     inside the 60-64px the brief asks for, arrived at by measuring rather
     than by hardcoding a height and hoping the contents fit. */
  padding: var(--space-3) var(--space-5);
  border-bottom: 1px solid var(--color-border);
  background: var(--color-surface);
}

/* ---- brand lockup ---- */

.pi-nav__brand {
  display: inline-flex;
  align-items: center;
  gap: 0.6rem;
  min-height: 34px;
  color: var(--color-text);
  text-decoration: none;
}
.pi-nav__brand:hover {
  text-decoration: none;
}
.pi-brand__mark {
  width: 28px;
  height: 28px;
  flex: none;
}
/* Wordmark set to brand/README.md's written spec: Perfex 600 in Ink, Insight
   700 in Signal, -0.022em tracking, and a 0.26em gap rather than a typed
   space. The mark beside it is the Final icon.svg, inlined verbatim. */
.pi-brand__word {
  display: inline-flex;
  gap: 0.26em;
  /* 19px, not 17px. At 17px the brand's own Signal blue on white measures
     3.68:1 against a 4.5 requirement; at 19px the bold wordmark is "large
     text", where the requirement is 3.0 and it passes with room. This keeps
     brand/README.md's specified colours exactly as written instead of
     recolouring the logo to satisfy a threshold, and a larger wordmark was
     wanted anyway. */
  font-size: 1.1875rem;
  letter-spacing: -0.022em;
  line-height: 1;
  white-space: nowrap;
}
.pi-brand__word-a {
  font-weight: var(--weight-semibold);
  color: var(--color-brand-ink);
}
.pi-brand__word-b {
  font-weight: var(--weight-bold);
  color: var(--color-brand-signal);
}

/* ---- primary links ---- */

.pi-nav__links {
  display: flex;
  align-items: center;
  gap: var(--space-5);
  margin-left: var(--space-4);
}
.pi-nav__links a {
  position: relative;
  min-height: 40px;
  display: inline-flex;
  align-items: center;
  color: var(--color-text-muted);
  font-size: var(--text-sm);
  font-weight: var(--weight-medium);
  text-decoration: none;
}
.pi-nav__links a:hover {
  color: var(--color-text);
  text-decoration: none;
}
/* The active marker is a 2px rule under the label only, not a pill, and it is
   drawn on a pseudo-element so it hugs the text rather than the 40px hit area
   the old inset box-shadow was painting under. */
.pi-nav__links a[aria-current="page"] {
  color: var(--color-text);
  font-weight: var(--weight-semibold);
}
.pi-nav__links a[aria-current="page"]::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  bottom: 6px;
  height: 2px;
  border-radius: 1px;
  background: var(--color-primary);
}

/* The panel exists only as a mobile container. On desktop it must not create a
   box of its own, or the links and the actions stack inside it instead of
   sitting on the nav's own flex line. */
.pi-nav__panel {
  display: contents;
}
.pi-nav__actions {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  margin-left: auto;
}
/* The header CTAs are navigation, not the page's primary call to action, so
   they sit a step below body-button size. */
.pi-nav__actions .pi-btn {
  min-height: 38px;
  padding-block: 0;
  font-size: var(--text-sm);
}

/* ---- mobile disclosure ----
   State is a checkbox, styling is :checked. No script, so the menu opens with
   JS disabled, and there is no framework on any public page. */

/* The checkbox is the control: it stays in the tab order and toggles on Space,
   which a <label tabindex="0"> does not — a label is focusable but not
   keyboard-activatable, so the first version of this menu could not be opened
   without a pointer. It is visually hidden rather than `hidden`, and the ring
   is drawn on the burger it sits behind. */
.pi-nav__toggle {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: 0;
  opacity: 0;
  pointer-events: none;
}
.pi-nav__burger {
  display: none;
  place-items: center;
  width: 44px;
  height: 44px;
  margin-left: auto;
  border: 1px solid var(--color-border-strong);
  border-radius: var(--radius-control);
  background: var(--color-surface);
  cursor: pointer;
}
.pi-nav__burger-bars,
.pi-nav__burger-bars::before,
.pi-nav__burger-bars::after {
  display: block;
  width: 17px;
  height: 2px;
  border-radius: 1px;
  background: var(--color-text);
}
.pi-nav__burger-bars {
  position: relative;
}
.pi-nav__burger-bars::before,
.pi-nav__burger-bars::after {
  content: "";
  position: absolute;
  left: 0;
}
.pi-nav__burger-bars::before {
  top: -5px;
}
.pi-nav__burger-bars::after {
  top: 5px;
}
.pi-nav__toggle:focus-visible + .pi-nav .pi-nav__burger {
  outline: var(--focus-width) solid var(--color-focus);
  outline-offset: var(--focus-offset);
}

@media (max-width: 860px) {
  .pi-nav {
    flex-wrap: wrap;
    gap: var(--space-3);
    padding: var(--space-3) var(--space-4);
  }
  /* Row one is brand + control and nothing else: the three-row ragged header
     came from letting links and two buttons wrap on their own. */
  .pi-nav__burger {
    display: grid;
  }
  /* Both row-one controls carry a full 44px target on touch. */
  .pi-nav__brand {
    min-height: 44px;
  }
  .pi-nav__panel {
    display: none;
    flex-basis: 100%;
    width: 100%;
    padding-bottom: var(--space-2);
  }
  .pi-nav__toggle:checked + .pi-nav .pi-nav__panel {
    display: block;
  }
  .pi-nav__links {
    display: grid;
    gap: 0;
    margin-left: 0;
    padding-top: var(--space-2);
    border-top: 1px solid var(--color-border);
  }
  .pi-nav__links a {
    min-height: 48px;
    font-size: var(--text-base);
  }
  .pi-nav__links a[aria-current="page"]::after {
    right: auto;
    width: 18px;
    bottom: 10px;
  }
  .pi-nav__actions {
    display: grid;
    gap: var(--space-2);
    margin-left: 0;
    padding-top: var(--space-3);
  }
  .pi-nav__actions .pi-btn {
    min-height: 46px;
    width: 100%;
  }
  /* Explore Add-ons is the priority action on a phone, so it leads the
     stack and Live Demo follows it. */
  .pi-nav__actions .pi-btn--primary {
    order: -1;
  }
}

/* Footer lockup: same mark, quieter wordmark, on the footer's own ground. */
.pi-brand--footer {
  margin-bottom: var(--space-3);
}

/* Visually hidden, still announced. Shared: three surfaces use it, and it was
   previously duplicated in two page layers and simply missing from the third,
   which printed the screen-reader text on the homepage's module tiles. */
.pi-sr {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
  border: 0;
}

/* ---------------- footer ----------------
   Shared by every public surface, so it lives here rather than in a page
   layer. Markup comes from the single partial landingpage/_src/footer.php. */

.pi-footer {
  border-top: 1px solid var(--color-border);
}
/* Padding added outside the measure, so footer columns land on the same left
   edge as the section headings above them. */
.pi-footer__grid {
  display: grid;
  grid-template-columns: 1.4fr repeat(3, 1fr);
  gap: var(--space-6);
  max-width: calc(var(--container) + 2 * var(--space-5));
  margin: 0 auto;
  padding: var(--space-7) var(--space-5) var(--space-5);
}
.pi-footer__grid h2 {
  margin-bottom: var(--space-3);
  font-size: var(--text-sm);
  font-weight: var(--weight-semibold);
  letter-spacing: 0.04em;
}
.pi-footer__grid a {
  display: flex;
  align-items: center;
  min-height: 44px;
  font-size: var(--text-sm);
  color: var(--color-text-muted);
}
.pi-footer__grid a:hover {
  color: var(--color-primary);
}
.pi-footer__grid .pi-nav__brand {
  margin-bottom: var(--space-2);
}
.pi-footer__grid p {
  font-size: var(--text-sm);
}
.pi-footer__legal {
  max-width: calc(var(--container) + 2 * var(--space-5));
  margin: 0 auto;
  padding: var(--space-4) var(--space-5) var(--space-6);
  border-top: 1px solid var(--color-border);
  font-size: var(--text-xs);
  color: var(--color-text-subtle);
}

/* ---------------- surfaces ---------------- */

.pi-on-dark {
  background: var(--color-surface-inverse);
  color: var(--color-text-inverse);
}
.pi-on-dark h1,
.pi-on-dark h2,
.pi-on-dark h3 {
  color: var(--color-text-inverse);
}
.pi-on-dark p {
  color: var(--color-text-inverse-muted);
}

.pi-panel {
  padding: var(--space-5);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-panel);
  background: var(--color-surface);
  box-shadow: var(--shadow-resting);
}

/* ---------------- responsive ----------------
   Five breakpoints. Only rules whose behaviour actually changes. */

@media (max-width: 1024px) {
  .pi-catalogue {
    grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
  }
  .pi-footer__grid {
    grid-template-columns: repeat(2, 1fr);
  }
}

@media (max-width: 768px) {
  .pi-nav {
    flex-wrap: wrap;
    gap: var(--space-3);
  }
  .pi-nav__links {
    order: 3;
    width: 100%;
    margin-left: 0;
    gap: var(--space-4);
    overflow-x: auto;
  }
  /* Brand and actions still share row 1 here, so keeping the actions right is
     correct: both edges are occupied and the row reads as a header. */
  .pi-nav__actions {
    margin-left: auto;
  }
  .pi-catalogue {
    grid-template-columns: 1fr;
  }
  .pi-card__actions {
    align-items: stretch;
  }
}

@media (max-width: 560px) {
  /* Below ~500px the brand and the two actions no longer fit on one row, so
     the actions wrapped to a line of their own while margin-left:auto still
     pinned them right — leaving a dead gap that read as a layout accident.
     Give them the full row deliberately instead, between brand and links. */
  .pi-nav__actions {
    order: 2;
    width: 100%;
    margin-left: 0;
  }
  .pi-nav__actions .pi-btn {
    flex: 1 1 0;
    justify-content: center;
  }
  .pi-card__head {
    flex-direction: column;
    gap: var(--space-1);
  }
  .pi-card__actions .pi-btn {
    flex: 1 1 auto;
  }
  .pi-group {
    flex-direction: column;
    gap: var(--space-1);
  }
  .pi-footer__grid {
    grid-template-columns: minmax(0, 1fr);
    gap: var(--space-5);
  }
}

/* ---------------- motion ----------------
   Content is visible at rest. Motion communicates state only. */

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