/**
 * Global stylesheet.
 *
 * Rules of the road:
 *   1. Components reference SEMANTIC tokens only (--pss-surface, --pss-accent).
 *      Never a raw hex. That is what makes every theme work everywhere.
 *   2. Color tokens come from src/lib/theme.ts and are injected into <head>.
 *      Everything below is the non-color half of the design system.
 *   3. Layout is fluid: clamp() and grid auto-fit rather than breakpoints,
 *      with a small number of explicit breakpoints where the design genuinely
 *      changes shape.
 */

/* ==========================================================================
   Non-color design tokens
   ========================================================================== */

:root {
  /* Type scale — fluid between a 360px and a 1400px viewport. */
  --pss-text-xs: 0.75rem;
  --pss-text-sm: 0.8125rem;
  --pss-text-base: 0.9375rem;
  --pss-text-md: 1rem;
  --pss-text-lg: clamp(1.0625rem, 0.98rem + 0.4vw, 1.25rem);
  --pss-text-xl: clamp(1.375rem, 1.2rem + 0.8vw, 1.75rem);
  --pss-text-2xl: clamp(1.75rem, 1.4rem + 1.6vw, 2.5rem);
  --pss-text-3xl: clamp(2.25rem, 1.6rem + 2.9vw, 4rem);
  --pss-text-stat: clamp(1.75rem, 1.3rem + 2vw, 2.75rem);

  /* Spacing */
  --pss-space-1: 0.25rem;
  --pss-space-2: 0.5rem;
  --pss-space-3: 0.75rem;
  --pss-space-4: 1rem;
  --pss-space-5: 1.5rem;
  --pss-space-6: 2rem;
  --pss-space-7: 3rem;
  --pss-space-8: 4rem;
  --pss-space-9: 6rem;
  /* Drives every band of vertical space: the padding on .section, the hero's
     bottom, and the CTA band. One lever, so the rhythm stays consistent. */
  --pss-section-y: clamp(2.25rem, 1.25rem + 4vw, 4.5rem);

  /* Shape */
  --pss-radius-sm: 6px;
  --pss-radius: 10px;
  --pss-radius-lg: 16px;
  --pss-radius-pill: 999px;

  /* Layout */
  --pss-container: 1200px;
  --pss-container-narrow: 900px;
  --pss-gutter: clamp(1.25rem, 0.8rem + 2vw, 2.5rem);

  /* Motion — all of it disabled below for reduced-motion users. */
  --pss-transition: 160ms cubic-bezier(0.4, 0, 0.2, 1);
}

/* ==========================================================================
   Reset
   ========================================================================== */

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

* {
  margin: 0;
}

html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
  /* Offset for the sticky header when jumping to an anchor. */
  scroll-padding-top: 6rem;
}

/* Applied by assets/js/photo-viewer.js while a modal dialog is open.
   showModal() makes the page inert but not unscrollable, so without this a
   wheel gesture over the backdrop moves the page behind the dialog.
   The padding replaces the width of the scrollbar that overflow:hidden
   removes, so locking does not shunt the layout sideways.
   scroll-behavior is reset because the smooth setting above would otherwise
   animate the jump back to position when the lock releases. */
html.pss-scroll-locked {
  overflow: hidden;
  padding-right: var(--pss-scrollbar-gap, 0px);
  scroll-behavior: auto;
}

body {
  min-height: 100dvh;
  background: var(--pss-bg);
  color: var(--pss-text);
  font-family: var(--font-sans), system-ui, -apple-system, 'Segoe UI', sans-serif;
  font-size: var(--pss-text-base);
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
  /* Color transitions make theme switching feel deliberate rather than jarring. */
  transition:
    background-color var(--pss-transition),
    color var(--pss-transition);
}

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

input,
button,
textarea,
select {
  font: inherit;
  color: inherit;
}

button {
  cursor: pointer;
  background: none;
  border: none;
  padding: 0;
}

a {
  color: inherit;
  text-decoration: none;
}

h1,
h2,
h3,
h4 {
  font-weight: 600;
  line-height: 1.12;
  letter-spacing: -0.02em;
  text-wrap: balance;
}

p {
  text-wrap: pretty;
}

ul,
ol {
  list-style: none;
  padding: 0;
}

:focus-visible {
  outline: 2px solid var(--pss-accent);
  outline-offset: 3px;
  border-radius: 3px;
}

::selection {
  background: var(--pss-accent);
  color: var(--pss-on-accent);
}

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

/* ==========================================================================
   Layout primitives
   ========================================================================== */

.container {
  width: 100%;
  max-width: var(--pss-container);
  margin-inline: auto;
  padding-inline: var(--pss-gutter);
}

.container--narrow {
  max-width: var(--pss-container-narrow);
}

.section {
  padding-block: var(--pss-section-y);
}

/* Pages without a hero open on a plain section. Give that first band the same
   tighter top as the hero, so every page sits the same distance below the
   header instead of the inner pages starting lower than the home page. */
main > .section:first-child {
  padding-top: clamp(1.75rem, 1rem + 3vw, 3.25rem);
}

.section--sunken {
  background: var(--pss-bg-sunken);
}

/* For a section that ends on something already visually heavy — the photo
   strip on a system page — where the full rhythm below leaves a hole. */
.section--tight-bottom {
  padding-bottom: var(--pss-space-6);
}

.section--bordered {
  border-top: 1px solid var(--pss-border);
}

.skip-link {
  position: absolute;
  left: -9999px;
  z-index: 999;
  padding: 0.75rem 1.25rem;
  background: var(--pss-accent);
  color: var(--pss-on-accent);
  border-radius: var(--pss-radius);
  font-weight: 600;
}

.skip-link:focus {
  left: var(--pss-gutter);
  top: 0.75rem;
}

/* ==========================================================================
   Shared type styles
   ========================================================================== */

.eyebrow {
  font-family: var(--font-mono), ui-monospace, monospace;
  font-size: var(--pss-text-xs);
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--pss-text-muted);
}

.section-head {
  display: flex;
  flex-wrap: wrap;
  align-items: end;
  justify-content: space-between;
  gap: var(--pss-space-4);
  margin-bottom: var(--pss-space-7);
}

/* Holds the download button and the "compare" link together, so they stay
   grouped against the right edge as the heading wraps. */
.section-head__actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--pss-space-4);
}

.btn__icon {
  width: 1em;
  height: 1em;
  flex: 0 0 auto;
}

/* No ch cap: these headings are written to sit on one line, and a measure
   limit was breaking them early. They still wrap on their own once the
   viewport is too narrow to hold them. */
.section-head__title {
  font-size: var(--pss-text-2xl);
  margin-top: var(--pss-space-3);
}

.section-head__lead {
  color: var(--pss-text-muted);
  max-width: 62ch;
  margin-top: var(--pss-space-4);
  font-size: var(--pss-text-lg);
}

.muted {
  color: var(--pss-text-muted);
}

/* ==========================================================================
   Buttons
   ========================================================================== */

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.5rem;
  padding: 0.7rem 1.25rem;
  border-radius: var(--pss-radius);
  border: 1px solid transparent;
  font-size: var(--pss-text-base);
  font-weight: 600;
  letter-spacing: -0.01em;
  white-space: nowrap;
  transition:
    background-color var(--pss-transition),
    border-color var(--pss-transition),
    color var(--pss-transition),
    transform var(--pss-transition);
}

.btn:active {
  transform: translateY(1px);
}

.btn--primary {
  background: var(--pss-accent);
  color: var(--pss-on-accent);
}

.btn--primary:hover {
  background: var(--pss-accent-hover);
}

.btn--secondary {
  border-color: var(--pss-border-strong);
  color: var(--pss-text);
}

.btn--secondary:hover {
  border-color: var(--pss-accent);
  color: var(--pss-accent);
}

.btn--ghost {
  color: var(--pss-text-muted);
  padding-inline: 0.5rem;
}

.btn--ghost:hover {
  color: var(--pss-text);
}

.btn--sm {
  padding: 0.45rem 0.85rem;
  font-size: var(--pss-text-sm);
}

/* A quiet text link with a moving arrow. */
.link-arrow {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  color: var(--pss-accent);
  font-weight: 600;
  font-size: var(--pss-text-base);
}

.link-arrow::after {
  content: '→';
  transition: transform var(--pss-transition);
}

.link-arrow:hover::after {
  transform: translateX(3px);
}

/* ==========================================================================
   Pills & chips
   ========================================================================== */

.pill {
  display: inline-flex;
  align-items: center;
  gap: 0.45rem;
  padding: 0.3rem 0.75rem;
  border-radius: var(--pss-radius-pill);
  background: var(--pss-accent-quiet);
  border: 1px solid var(--pss-accent-line);
  color: var(--pss-accent);
  font-family: var(--font-mono), ui-monospace, monospace;
  font-size: var(--pss-text-xs);
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.chip {
  display: inline-block;
  padding: 0.3rem 0.7rem;
  border-radius: var(--pss-radius-sm);
  border: 1px solid var(--pss-border);
  background: var(--pss-surface-raised);
  color: var(--pss-text-muted);
  font-family: var(--font-mono), ui-monospace, monospace;
  font-size: var(--pss-text-xs);
}

.chip-list {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
}

/* ==========================================================================
   Header
   ========================================================================== */

.site-header {
  position: sticky;
  top: 0;
  z-index: 100;
  background: color-mix(in srgb, var(--pss-bg) 88%, transparent);
  backdrop-filter: blur(12px);
  border-bottom: 1px solid var(--pss-border);
}

.site-header__inner {
  display: flex;
  align-items: center;
  gap: var(--pss-space-5);
  min-height: 4.25rem;
}

.brand {
  display: flex;
  flex-direction: column;
  line-height: 1.2;
  margin-right: auto;
}

.brand__name {
  font-size: var(--pss-text-md);
  font-weight: 700;
  letter-spacing: -0.02em;
}

.brand__line {
  font-family: var(--font-mono), ui-monospace, monospace;
  font-size: var(--pss-text-xs);
  color: var(--pss-text-muted);
  letter-spacing: 0.04em;
}

.nav {
  display: flex;
  align-items: center;
  gap: var(--pss-space-5);
}

.nav__link {
  font-size: var(--pss-text-base);
  color: var(--pss-text-muted);
  transition: color var(--pss-transition);
}

.nav__link:hover,
.nav__link[aria-current='page'] {
  color: var(--pss-text);
}

.nav__link[aria-current='page'] {
  color: var(--pss-accent);
}

.header__actions {
  display: flex;
  align-items: center;
  gap: var(--pss-space-3);
}

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

.nav-toggle {
  display: none;
  width: 2.5rem;
  height: 2.5rem;
  align-items: center;
  justify-content: center;
  border: 1px solid var(--pss-border);
  border-radius: var(--pss-radius-sm);
  color: var(--pss-text-muted);
}

@media (max-width: 900px) {
  .nav-toggle {
    display: inline-flex;
  }

  .nav {
    position: fixed;
    inset: 4.25rem 0 auto 0;
    flex-direction: column;
    align-items: stretch;
    gap: 0;
    padding: var(--pss-space-4) var(--pss-gutter) var(--pss-space-6);
    background: var(--pss-bg);
    border-bottom: 1px solid var(--pss-border);
    /* Hidden by default; toggled by the header component. */
    display: none;
  }

  .nav[data-open='true'] {
    display: flex;
  }

  .nav__link {
    padding-block: 0.8rem;
    border-bottom: 1px solid var(--pss-border);
    font-size: var(--pss-text-lg);
  }

  .header__cta {
    display: none;
  }
}

/* ==========================================================================
   Hero
   ========================================================================== */

.hero {
  position: relative;
  padding-block: clamp(1.75rem, 1rem + 3vw, 3.25rem) var(--pss-section-y);
  overflow: hidden;
}

/* A soft accent wash behind the headline. */
.hero::before {
  content: '';
  position: absolute;
  top: -30%;
  left: 50%;
  width: min(1100px, 130%);
  aspect-ratio: 2 / 1;
  transform: translateX(-50%);
  background: radial-gradient(
    ellipse at center,
    color-mix(in srgb, var(--pss-accent) 13%, transparent) 0%,
    transparent 68%
  );
  pointer-events: none;
  z-index: 0;
}

.hero__inner {
  position: relative;
  z-index: 1;
  display: grid;
  gap: var(--pss-space-7);
  grid-template-columns: minmax(0, 1fr);
}

.hero--with-image .hero__inner {
  /* An even split: words and image carry equal weight. */
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--pss-space-6);
  /* Top-aligned rather than centered, so the frame can line up with the
     headline instead of floating against the middle of the column. */
  align-items: start;
}

.hero--with-image .hero__media {
  padding: var(--pss-space-2);
}

/* Drop the frame to the headline's first line. The eyebrow pill sits above
   the headline, so the offset is the pill's own height plus the gap the
   headline already carries. `:has()` keeps it correct when there is no pill. */
.hero--with-image:has(.hero__inner .pill) .hero__media {
  --pss-pill-height: calc(var(--pss-text-xs) * 1.6 + 0.6rem + 2px);
  margin-top: calc(var(--pss-pill-height) + var(--pss-space-5));
}

@media (max-width: 900px) {
  .hero--with-image .hero__inner {
    grid-template-columns: minmax(0, 1fr);
  }
  .hero--with-image:has(.hero__inner .pill) .hero__media {
    margin-top: 0;
  }
  .hero--with-image .hero__media {
    margin-inline: 0;
    padding: var(--pss-space-4);
  }
}

.hero__title {
  font-size: var(--pss-text-3xl);
  max-width: 16ch;
  margin-top: var(--pss-space-5);
}

.hero__title-accent {
  display: block;
  color: var(--pss-accent);
}

.hero__text {
  margin-top: var(--pss-space-5);
  max-width: 52ch;
  font-size: var(--pss-text-lg);
  color: var(--pss-text-muted);
}

.hero__actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--pss-space-3);
  margin-top: var(--pss-space-6);
}

/* A grid rather than wrapping flex: the points line up in columns instead of
   ending in a ragged second row. */
.hero__points {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(13rem, 1fr));
  gap: var(--pss-space-3) var(--pss-space-5);
  margin-top: var(--pss-space-6);
}

.hero__point {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  font-size: var(--pss-text-sm);
  color: var(--pss-text-muted);
}

.hero__point::before {
  content: '▸';
  color: var(--pss-accent);
}

.hero__media {
  border: 1px solid var(--pss-border);
  border-radius: var(--pss-radius-lg);
  background: var(--pss-surface);
  padding: var(--pss-space-4);
  box-shadow: var(--pss-shadow);
}

.hero__media img {
  border-radius: var(--pss-radius);
  width: 100%;
}

/* Statistics strip ------------------------------------------------------- */

.stats-strip {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(9rem, 1fr));
  gap: 1px;
  margin-top: var(--pss-space-8);
  background: var(--pss-border);
  border: 1px solid var(--pss-border);
  border-radius: var(--pss-radius-lg);
  overflow: hidden;
}

.stat {
  background: var(--pss-surface);
  padding: var(--pss-space-5);
}

.stat__value {
  font-size: var(--pss-text-xl);
  font-weight: 700;
  letter-spacing: -0.03em;
  color: var(--pss-accent);
  font-variant-numeric: tabular-nums;
}

.stat__label {
  margin-top: 0.2rem;
  font-size: var(--pss-text-sm);
  color: var(--pss-text-muted);
}

/* ==========================================================================
   Cards
   ========================================================================== */

.card {
  display: flex;
  flex-direction: column;
  background: var(--pss-surface);
  border: 1px solid var(--pss-border);
  border-radius: var(--pss-radius-lg);
  padding: var(--pss-space-6);
  transition:
    border-color var(--pss-transition),
    transform var(--pss-transition),
    box-shadow var(--pss-transition);
}

.card--interactive:hover {
  border-color: var(--pss-accent-line);
  transform: translateY(-2px);
  box-shadow: var(--pss-shadow);
}

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

/* System card ------------------------------------------------------------ */

.system-card__head {
  display: flex;
  /* Was baseline, which worked when the right-hand side was a text link. It
     now holds buttons, whose baseline sits well below their box and dragged
     the title down with it. */
  align-items: center;
  justify-content: space-between;
  gap: var(--pss-space-3);
}

.system-card__title {
  font-size: var(--pss-text-xl);
}

/* Right-hand group in the card head: kind of machine, then its datasheet.
   Wraps rather than crowding the title on a narrow card. */
.system-card__meta {
  display: flex;
  align-items: baseline;
  justify-content: flex-end;
  flex-wrap: wrap;
  gap: var(--pss-space-3);
}

.system-card__subtitle {
  font-family: var(--font-mono), ui-monospace, monospace;
  font-size: var(--pss-text-xs);
  color: var(--pss-text-muted);
  letter-spacing: 0.06em;
  text-transform: uppercase;
}

/* View / download, top right of a system card head. */
.datasheet-actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--pss-space-2);
}

/* ==========================================================================
   Document dialog: a datasheet PDF, read without leaving the page.
   ========================================================================== */

.doc-dialog {
  width: min(58rem, 94vw);
  max-width: none;
  height: min(46rem, 90vh);
  max-height: 90vh;
  padding: 0;
  border: 0;
  background: transparent;
  overflow: visible;
  /* Same reason as .photo-dialog: the global margin reset wipes the UA's
     `margin: auto`, which is what centers a modal. */
  margin: auto;
}

.doc-dialog::backdrop {
  background: rgb(0 0 0 / 0.7);
  backdrop-filter: blur(3px);
}

.doc-dialog__panel {
  display: flex;
  flex-direction: column;
  height: 100%;
  border: 1px solid var(--pss-border-strong);
  border-radius: var(--pss-radius-lg);
  background: var(--pss-surface);
  box-shadow: var(--pss-shadow);
  overflow: hidden;
}

.doc-dialog__bar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--pss-space-4);
  padding: var(--pss-space-3) var(--pss-space-3) var(--pss-space-3) var(--pss-space-5);
  border-bottom: 1px solid var(--pss-border);
  background: var(--pss-bg-sunken);
}

.doc-dialog__title {
  font-family: var(--font-mono), ui-monospace, monospace;
  font-size: var(--pss-text-xs);
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--pss-text-muted);
}

.doc-dialog__actions {
  display: flex;
  align-items: center;
  gap: var(--pss-space-2);
}

.doc-dialog__close {
  display: grid;
  place-items: center;
  width: 2rem;
  height: 2rem;
  border: 1px solid var(--pss-border);
  border-radius: var(--pss-radius-sm);
  background: var(--pss-surface);
  color: var(--pss-text-muted);
  cursor: pointer;
  transition:
    color var(--pss-transition),
    border-color var(--pss-transition);
}

.doc-dialog__close:hover {
  color: var(--pss-text);
  border-color: var(--pss-border-strong);
}

.doc-dialog__close svg {
  width: 1rem;
  height: 1rem;
}

/* The PDF itself. White, because that is what the document is, and boxing it
   in the page's near-black would only make the page look broken. */
.doc-dialog__frame {
  flex: 1;
  width: 100%;
  min-height: 0;
  border: 0;
  background: #ffffff;
}

.doc-dialog__fallback {
  padding: var(--pss-space-6);
  color: var(--pss-text-muted);
  font-size: var(--pss-text-sm);
}

.doc-dialog__fallback a {
  color: var(--pss-accent);
  text-decoration: underline;
}

.system-card__photo {
  margin: var(--pss-space-5) calc(var(--pss-space-6) * -1) 0;
  border-block: 1px solid var(--pss-border);
  background: var(--pss-bg-sunken);
}

/* A fixed frame with `contain`, not `cover`: product photos come in mixed
   orientations (the rack unit is landscape, the tower portrait) and cropping a
   machine to fill a box is worse than letterboxing it. 4/3 is the compromise
   that leaves neither orientation looking stranded. */
.system-card__photo img {
  width: 100%;
  aspect-ratio: 4 / 3;
  object-fit: contain;
  padding: var(--pss-space-4);
}

.system-card__blurb {
  margin-top: var(--pss-space-4);
  color: var(--pss-text-muted);
}

/* Line the spec rows up across the two system cards.

   The cards are equal height already, but their blurbs are not: one runs to
   two lines and the other to three, so every row below started one line out of
   step and the pair read as sloppy. Letting the blurb absorb the slack pushes
   the shorter card's spec list down to meet the taller one, so GPUs sits level
   with GPUs, Cores with Cores, and so on.

   Deliberately not subgrid, which would do the same job but break the moment a
   machine is published without a photo and its row count stops matching. */
.card--interactive .system-card__blurb {
  flex: 1;
}

.spec-list {
  margin-top: var(--pss-space-5);
  border-top: 1px solid var(--pss-border);
}

.spec-list__row {
  display: flex;
  justify-content: space-between;
  gap: var(--pss-space-4);
  padding-block: 0.6rem;
  border-bottom: 1px solid var(--pss-border);
  font-size: var(--pss-text-sm);
}

.spec-list__label {
  color: var(--pss-text-muted);
}

.spec-list__value {
  text-align: right;
  font-family: var(--font-mono), ui-monospace, monospace;
  font-size: var(--pss-text-xs);
}

.card__footer {
  margin-top: auto;
  padding-top: var(--pss-space-5);
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--pss-space-4);
}

.system-card__price {
  font-family: var(--font-mono), ui-monospace, monospace;
  font-size: var(--pss-text-md);
  font-weight: 500;
  letter-spacing: -0.02em;
  color: var(--pss-text);
  white-space: nowrap;
}

/* ==========================================================================
   Comparison table
   ========================================================================== */

.compare {
  border: 1px solid var(--pss-border);
  border-radius: var(--pss-radius-lg);
  overflow-x: auto;
  background: var(--pss-surface);
}

.compare table {
  width: 100%;
  min-width: 40rem;
  border-collapse: collapse;
}

.compare th,
.compare td {
  padding: var(--pss-space-4) var(--pss-space-5);
  text-align: left;
  border-bottom: 1px solid var(--pss-border);
  vertical-align: top;
}

.compare tbody tr:last-child th,
.compare tbody tr:last-child td {
  border-bottom: none;
}

.compare thead th {
  background: var(--pss-bg-sunken);
  font-size: var(--pss-text-lg);
  letter-spacing: -0.02em;
}

.compare thead th span {
  display: block;
  margin-top: 0.15rem;
  font-family: var(--font-mono), ui-monospace, monospace;
  font-size: var(--pss-text-xs);
  font-weight: 400;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--pss-text-muted);
}

.compare tbody th {
  font-weight: 400;
  color: var(--pss-text-muted);
  font-size: var(--pss-text-sm);
  width: 30%;
}

.compare td {
  font-family: var(--font-mono), ui-monospace, monospace;
  font-size: var(--pss-text-sm);
}

.compare tbody tr:hover td,
.compare tbody tr:hover th {
  background: var(--pss-accent-quiet);
}

/* ==========================================================================
   Detail page
   ========================================================================== */

.detail-hero {
  display: grid;
  gap: var(--pss-space-7);
  grid-template-columns: minmax(0, 1.4fr) minmax(0, 1fr);
  align-items: start;
}

@media (max-width: 900px) {
  .detail-hero {
    grid-template-columns: minmax(0, 1fr);
  }
}

.detail-hero__title {
  font-size: var(--pss-text-3xl);
  margin-top: var(--pss-space-3);
}

.detail-hero__lede {
  margin-top: var(--pss-space-5);
  font-size: var(--pss-text-lg);
  color: var(--pss-text-muted);
  max-width: 60ch;
}

/* The asking price, directly above the quote button it belongs to. */
.detail-hero__price {
  margin-top: var(--pss-space-5);
  font-family: var(--font-mono), ui-monospace, monospace;
  font-size: var(--pss-text-2xl);
  font-weight: 500;
  letter-spacing: -0.03em;
  color: var(--pss-text);
}

.detail-hero__price span {
  display: block;
  margin-top: var(--pss-space-1);
  font-family: inherit;
  font-size: var(--pss-text-xs);
  font-weight: 400;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--pss-text-faint);
}

/* ==========================================================================
   Callout — a single commercial term, stated once and reused.
   ========================================================================== */

.callout {
  display: flex;
  align-items: flex-start;
  gap: 0.6rem;
  padding: var(--pss-space-4);
  border: 1px solid var(--pss-accent-line);
  border-radius: var(--pss-radius);
  background: var(--pss-accent-quiet);
  color: var(--pss-text);
  font-size: var(--pss-text-sm);
}

.callout__icon {
  flex: none;
  width: 1.15rem;
  height: 1.15rem;
  margin-top: 0.05rem;
  color: var(--pss-accent);
}

/* Under a spec table the box would fight the table's own border, so the
   compact variant is just the line. */
.callout--compact {
  padding: 0;
  border: none;
  background: none;
  color: var(--pss-text-muted);
}

.detail-stats {
  display: grid;
  gap: var(--pss-space-4);
}

.detail-stat {
  border: 1px solid var(--pss-border);
  border-radius: var(--pss-radius-lg);
  background: var(--pss-surface);
  padding: var(--pss-space-5);
}

.detail-stat__value {
  font-size: var(--pss-text-stat);
  font-weight: 700;
  letter-spacing: -0.035em;
  color: var(--pss-accent);
  font-variant-numeric: tabular-nums;
  line-height: 1;
}

.detail-stat__label {
  margin-top: var(--pss-space-2);
  font-size: var(--pss-text-sm);
  color: var(--pss-text-muted);
}

/* ==========================================================================
   Product photo + enlarged view
   ========================================================================== */

/* A system's photos, all on one line.
   `flex: 1 1 0` with `min-width: 0` shares the row evenly and lets the tiles
   shrink past their image's intrinsic width — without the min-width override a
   flex item refuses to go below its content and the last photo wraps away. */
.photo-grid {
  display: flex;
  gap: var(--pss-space-4);
  align-items: flex-start;
}

.photo-grid .photo {
  flex: 1 1 0;
  min-width: 0;
  width: auto;
}

.photo-grid .photo__thumb {
  width: 100%;
}

/* Below the tablet breakpoint one row of three is too small to read; let them
   wrap two-up instead. */
@media (max-width: 900px) {
  .photo-grid {
    flex-wrap: wrap;
  }

  .photo-grid .photo {
    flex: 1 1 13rem;
  }
}

.photo {
  margin: 0;
  width: fit-content;
}

.photo__thumb {
  display: block;
  position: relative;
  width: min(22rem, 100%);
  padding: var(--pss-space-3);
  background: var(--pss-surface);
  border: 1px solid var(--pss-border);
  border-radius: var(--pss-radius-lg);
  cursor: zoom-in;
  transition:
    border-color var(--pss-transition),
    box-shadow var(--pss-transition);
}

.photo__thumb:hover {
  border-color: var(--pss-accent-line);
  box-shadow: var(--pss-shadow);
}

/* `contain`, not `cover`: the rack unit is landscape and the tower portrait,
   and cropping a machine to fill a box is worse than letterboxing it. */
.photo__thumb img {
  width: 100%;
  height: auto;
  aspect-ratio: 4 / 3;
  object-fit: contain;
  border-radius: var(--pss-radius);
}

.photo__expand {
  position: absolute;
  right: var(--pss-space-4);
  bottom: var(--pss-space-4);
  display: grid;
  place-items: center;
  width: 2rem;
  height: 2rem;
  border-radius: var(--pss-radius-sm);
  background: var(--pss-accent);
  color: var(--pss-on-accent);
  box-shadow: var(--pss-shadow-sm);
}

.photo__expand svg {
  width: 0.95rem;
  height: 0.95rem;
}

.photo__hint {
  margin-top: var(--pss-space-2);
  font-family: var(--font-mono), ui-monospace, monospace;
  font-size: var(--pss-text-xs);
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--pss-text-muted);
}

/* --- the enlarged view ---------------------------------------------------- */

.photo-dialog {
  /* Deliberately smaller than the full-bleed photo this replaced. */
  width: min(44rem, 92vw);
  max-width: none;
  max-height: 90vh;
  padding: 0;
  border: 0;
  background: transparent;
  overflow: visible;
  /* The `* { margin: 0 }` reset above wipes the UA stylesheet's `margin: auto`,
     which is what centers a modal dialog inside its `inset: 0` box. Without
     this the dialog pins to the top-left corner. */
  margin: auto;
}

.photo-dialog::backdrop {
  background: rgb(0 0 0 / 0.7);
  backdrop-filter: blur(3px);
}

.photo-dialog__panel {
  position: relative;
  padding: var(--pss-space-4);
  background: var(--pss-surface);
  border: 1px solid var(--pss-border);
  border-radius: var(--pss-radius-lg);
  box-shadow: var(--pss-shadow);
}

.photo-dialog__panel img {
  width: 100%;
  height: auto;
  max-height: 70vh;
  object-fit: contain;
  border-radius: var(--pss-radius);
}

.photo-dialog__close {
  position: absolute;
  top: calc(var(--pss-space-3) * -1);
  right: calc(var(--pss-space-3) * -1);
  display: grid;
  place-items: center;
  width: 2.25rem;
  height: 2.25rem;
  border-radius: 50%;
  background: var(--pss-surface-raised);
  border: 1px solid var(--pss-border-strong);
  color: var(--pss-text);
  box-shadow: var(--pss-shadow-sm);
  transition:
    color var(--pss-transition),
    border-color var(--pss-transition);
}

.photo-dialog__close:hover {
  color: var(--pss-accent);
  border-color: var(--pss-accent);
}

.photo-dialog__close svg {
  width: 1.05rem;
  height: 1.05rem;
}

.photo-dialog__caption {
  margin-top: var(--pss-space-3);
  font-size: var(--pss-text-sm);
  color: var(--pss-text-muted);
}

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

.panel {
  background: var(--pss-surface);
  border: 1px solid var(--pss-border);
  border-radius: var(--pss-radius-lg);
  padding: var(--pss-space-6);
}

.panel__title {
  font-size: var(--pss-text-lg);
  margin-bottom: var(--pss-space-4);
}

/* ==========================================================================
   Numbered / bulleted lists
   ========================================================================== */

.check-list {
  display: grid;
  gap: var(--pss-space-3);
}

.check-list li {
  display: grid;
  grid-template-columns: 1.25rem 1fr;
  gap: 0.6rem;
  color: var(--pss-text-muted);
  font-size: var(--pss-text-base);
}

.check-list li::before {
  content: '✓';
  color: var(--pss-accent);
  font-weight: 700;
}

/* The poor-fit column. Same list, opposite mark — muted rather than red,
   because these are honest limits, not errors. */
.cross-list li::before {
  content: '✕';
  color: var(--pss-text-faint);
}

/* A hairline down the inside edge tells the two fit panels apart without
   colouring whole cards, which would read as a warning banner. */
.panel--good {
  border-left: 2px solid var(--pss-accent-line);
}

.panel--caution {
  border-left: 2px solid var(--pss-border-strong);
}

/* ==========================================================================
   Chooser: one card per machine, on /systems/.
   ========================================================================== */

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

.choose-card {
  display: flex;
  flex-direction: column;
  padding: var(--pss-space-6);
  border: 1px solid var(--pss-border);
  border-radius: var(--pss-radius-lg);
  background: var(--pss-surface);
}

.choose-card__eyebrow,
.choose-card__label {
  font-family: var(--font-mono), ui-monospace, monospace;
  font-size: var(--pss-text-xs);
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--pss-text-faint);
}

.choose-card__title {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--pss-space-4);
  margin-top: var(--pss-space-2);
  font-size: var(--pss-text-xl);
  letter-spacing: -0.02em;
}

.choose-card__price {
  font-family: var(--font-mono), ui-monospace, monospace;
  font-size: var(--pss-text-md);
  font-weight: 500;
  letter-spacing: -0.02em;
  color: var(--pss-accent);
  white-space: nowrap;
}

.choose-card__subtitle {
  margin-top: var(--pss-space-1);
  font-size: var(--pss-text-sm);
  color: var(--pss-text-muted);
}

/* The "if" sits between the machine and its conditions, so the card reads as
   one sentence: "Choose the T7910 if / it lives in an office". */
.choose-card__label {
  margin-top: var(--pss-space-5);
}

.choose-card__points {
  margin-top: var(--pss-space-3);
}

/* Short phrases, so they should not carry the muted body colour that made the
   old table's third column so easy to skip. */
.choose-card__points li {
  color: var(--pss-text);
}

.choose-card__footer {
  margin-top: auto;
  padding-top: var(--pss-space-5);
}

/* The one case where the answer is no. Centred under both cards, because it
   belongs to neither. */
.choose-note {
  margin-top: var(--pss-space-5);
  padding: var(--pss-space-4) var(--pss-space-5);
  border: 1px dashed var(--pss-border-strong);
  border-radius: var(--pss-radius);
  text-align: center;
  font-size: var(--pss-text-sm);
  color: var(--pss-text-muted);
}

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

.numbered__index {
  font-family: var(--font-mono), ui-monospace, monospace;
  font-size: var(--pss-text-xs);
  letter-spacing: 0.12em;
  color: var(--pss-accent);
}

.numbered__title {
  margin-top: var(--pss-space-3);
  font-size: var(--pss-text-md);
}

.numbered__text {
  margin-top: var(--pss-space-2);
  color: var(--pss-text-muted);
  font-size: var(--pss-text-sm);
}

/* ==========================================================================
   Software stack
   ========================================================================== */

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

.stack-group__title {
  font-family: var(--font-mono), ui-monospace, monospace;
  font-size: var(--pss-text-xs);
  text-transform: uppercase;
  letter-spacing: 0.12em;
  color: var(--pss-text-muted);
  padding-bottom: var(--pss-space-3);
  border-bottom: 1px solid var(--pss-accent-line);
}

.stack-group__items {
  margin-top: var(--pss-space-4);
  display: grid;
  gap: var(--pss-space-2);
}

.stack-group__items li {
  font-size: var(--pss-text-base);
}

/* ==========================================================================
   Terminal
   ========================================================================== */

.terminal {
  border: 1px solid var(--pss-border);
  border-radius: var(--pss-radius-lg);
  overflow: hidden;
  background: var(--pss-code-bg);
}

.terminal__bar {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.65rem var(--pss-space-4);
  background: color-mix(in srgb, var(--pss-code-bg) 82%, #808080);
  border-bottom: 1px solid var(--pss-border);
}

.terminal__dot {
  width: 0.6rem;
  height: 0.6rem;
  border-radius: 50%;
  background: color-mix(in srgb, var(--pss-code-text) 35%, transparent);
}

.terminal__title {
  margin-left: 0.5rem;
  font-family: var(--font-mono), ui-monospace, monospace;
  font-size: var(--pss-text-xs);
  color: color-mix(in srgb, var(--pss-code-text) 70%, transparent);
}

.terminal__body {
  padding: var(--pss-space-5);
  font-family: var(--font-mono), ui-monospace, monospace;
  font-size: var(--pss-text-sm);
  line-height: 1.8;
  color: var(--pss-code-text);
  overflow-x: auto;
}

.terminal__line--command {
  color: var(--pss-accent-dark);
}

.terminal__line--command::before {
  content: '$ ';
  opacity: 0.6;
}

.terminal__line--output {
  color: color-mix(in srgb, var(--pss-code-text) 70%, transparent);
}

/* ==========================================================================
   Testimonials
   ========================================================================== */

.quote {
  display: flex;
  flex-direction: column;
  gap: var(--pss-space-4);
  height: 100%;
}

.quote__text {
  font-size: var(--pss-text-lg);
  letter-spacing: -0.01em;
}

.quote__attribution {
  margin-top: auto;
  font-family: var(--font-mono), ui-monospace, monospace;
  font-size: var(--pss-text-xs);
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--pss-text-muted);
}

/* ==========================================================================
   Call-to-action band
   ========================================================================== */

.cta-band {
  text-align: center;
  padding-block: var(--pss-section-y);
  border-top: 1px solid var(--pss-border);
  background:
    radial-gradient(
      ellipse at 50% 0%,
      color-mix(in srgb, var(--pss-accent) 10%, transparent) 0%,
      transparent 60%
    ),
    var(--pss-bg);
}

.cta-band__title {
  font-size: var(--pss-text-2xl);
  margin-inline: auto;
}

.cta-band__text {
  margin: var(--pss-space-4) auto 0;
  max-width: 52ch;
  color: var(--pss-text-muted);
  font-size: var(--pss-text-lg);
}

.cta-band__actions {
  margin-top: var(--pss-space-6);
  display: flex;
  justify-content: center;
  gap: var(--pss-space-3);
  flex-wrap: wrap;
}

/* ==========================================================================
   Forms
   ========================================================================== */

.form {
  display: grid;
  gap: var(--pss-space-5);
}

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

/* Groups the build questions so the form reads as two short sections rather
   than one long column of eleven inputs. A real <fieldset>/<legend>, so screen
   readers announce the grouping too. */
.fieldset {
  display: grid;
  gap: var(--pss-space-5);
  padding: var(--pss-space-5);
  border: 1px solid var(--pss-border);
  border-radius: var(--pss-radius-lg);
  background: var(--pss-bg-sunken);
}

.fieldset__legend {
  padding: 0 var(--pss-space-2);
  font-family: var(--font-mono), ui-monospace, monospace;
  font-size: var(--pss-text-xs);
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--pss-text-muted);
}

/* Sits directly under the legend, so it loses the grid gap it would otherwise
   inherit and read as a separate row. */
.fieldset__hint {
  margin-top: calc(var(--pss-space-5) * -1 + var(--pss-space-2));
  font-size: var(--pss-text-sm);
  color: var(--pss-text-faint);
}

/* Inputs inside the fieldset sit on the sunken panel, so they need the raised
   surface to stay distinguishable from it. */
.fieldset .field__control {
  background: var(--pss-surface);
}

.field {
  display: grid;
  gap: var(--pss-space-2);
}

.field__label {
  font-size: var(--pss-text-sm);
  color: var(--pss-text-muted);
}

.field__label .required {
  color: var(--pss-accent);
}

.field__control {
  width: 100%;
  padding: 0.7rem 0.9rem;
  background: var(--pss-bg-sunken);
  border: 1px solid var(--pss-border);
  border-radius: var(--pss-radius);
  color: var(--pss-text);
  transition:
    border-color var(--pss-transition),
    background-color var(--pss-transition);
}

.field__control::placeholder {
  color: var(--pss-text-faint);
}

.field__control:focus {
  outline: none;
  border-color: var(--pss-accent);
  background: var(--pss-surface);
}

.field__control[aria-invalid='true'] {
  border-color: #e5484d;
}

.field__error {
  font-size: var(--pss-text-sm);
  color: #e5484d;
}

textarea.field__control {
  resize: vertical;
  min-height: 8rem;
}

.form__status {
  padding: var(--pss-space-5);
  border: 1px solid var(--pss-accent-line);
  background: var(--pss-accent-quiet);
  border-radius: var(--pss-radius);
}

.form__status-title {
  font-size: var(--pss-text-lg);
  color: var(--pss-accent);
}

.form__status-text {
  margin-top: var(--pss-space-2);
  color: var(--pss-text-muted);
}

/* Honeypot: hidden from people, visible to naive bots. */
.hp-field {
  position: absolute;
  left: -9999px;
  width: 1px;
  height: 1px;
  overflow: hidden;
}

/* ==========================================================================
   Definition rows (contact details, at-a-glance)
   ========================================================================== */

.def-list {
  display: grid;
  gap: 0;
}

.def-list__row {
  display: flex;
  justify-content: space-between;
  gap: var(--pss-space-4);
  padding-block: 0.7rem;
  border-bottom: 1px solid var(--pss-border);
  font-size: var(--pss-text-base);
}

.def-list__row:last-child {
  border-bottom: none;
}

.def-list__label {
  color: var(--pss-text-muted);
}

.def-list__value {
  text-align: right;
}

/* ==========================================================================
   Footer
   ========================================================================== */

.site-footer {
  border-top: 1px solid var(--pss-border);
  background: var(--pss-bg-sunken);
  padding-block: var(--pss-space-8) var(--pss-space-6);
}

.site-footer__grid {
  display: grid;
  gap: var(--pss-space-6);
  grid-template-columns: minmax(0, 1.6fr) repeat(auto-fit, minmax(9rem, 1fr));
}

.site-footer__title {
  font-size: var(--pss-text-md);
  font-weight: 700;
}

.site-footer__blurb {
  margin-top: var(--pss-space-3);
  color: var(--pss-text-muted);
  font-size: var(--pss-text-sm);
  max-width: 40ch;
}

.site-footer__heading {
  font-family: var(--font-mono), ui-monospace, monospace;
  font-size: var(--pss-text-xs);
  text-transform: uppercase;
  letter-spacing: 0.12em;
  color: var(--pss-text-faint);
  margin-bottom: var(--pss-space-3);
}

.site-footer__list {
  display: grid;
  gap: var(--pss-space-2);
  font-size: var(--pss-text-sm);
  color: var(--pss-text-muted);
}

.site-footer__list a:hover {
  color: var(--pss-accent);
}

.site-footer__bottom {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  gap: var(--pss-space-3);
  margin-top: var(--pss-space-7);
  padding-top: var(--pss-space-5);
  border-top: 1px solid var(--pss-border);
  font-size: var(--pss-text-xs);
  color: var(--pss-text-faint);
}

.site-footer__note {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
}

.site-footer__portfolio {
  display: inline-flex;
  align-items: center;
  color: var(--pss-text-faint);
  transition: color var(--pss-transition);
}

.site-footer__portfolio:hover,
.site-footer__portfolio:focus-visible {
  color: var(--pss-accent);
}

/* ==========================================================================
   Utilities
   ========================================================================== */

.stack-sm > * + * {
  margin-top: var(--pss-space-3);
}

.stack-md > * + * {
  margin-top: var(--pss-space-5);
}

.stack-lg > * + * {
  margin-top: var(--pss-space-7);
}

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

.prose p + p {
  margin-top: var(--pss-space-4);
}

.prose {
  color: var(--pss-text-muted);
  max-width: 68ch;
}
