/* ===========================================================================
   Proteus product homepage - design system and section layout.

   Tokens come from design-tokens.css, which is the same file the product GUI
   and the documentation load. Never override a --p-* value here. Where this
   file needs a name the kit does not provide, it defines a --s-* semantic
   token whose value is taken from the kit (source noted in a comment).

   Owned by brand-ui. Anything named .pterm-* belongs to terminal.css, and
   anything named .c-* belongs to content.css. This file styles neither.
   =========================================================================== */

:root {
  /* Layout */
  --s-max: 1280px;
  --s-gutter: clamp(20px, 4vw, 44px);
  --s-section-y: clamp(56px, 7vw, 104px);

  /* The hero animation slot owns its size through this ratio. See #hero-stage.
     16/10 rather than 4/3: the banner is 2.5:1, so a cover crop at 1.6 shows the
     chameleon AND most of its pixel trail, where 1.333 cut the trail off. */
  --s-stage-ratio: 16 / 10;

  /* How far a full-bleed element reaches past the capped container on one side.
     0 until the viewport is wider than --s-max, then half the slack. */
  --s-bleed: max(0px, calc((100vw - var(--s-max)) / 2));

  /* Terminal-style code surfaces. A transcript stays dark in both themes;
     these three values are lifted from proteus-web-kit ui/styles.css .code */
  --s-code-bg: var(--p-forest-950);
  --s-code-fg: #b4eacd;
  --s-code-border: #315240;

  /* The dark full-bleed band before the footer, from the kit .cta rule. */
  --s-band-bg: var(--p-forest-900);
  --s-band-fg: #ffffff;
  --s-band-muted: #c3e8d4;

  /* Interactive outlines need 3:1 against their background, which --p-border
     does not reach. Secondary controls use the accent for their edge instead. */
  --s-control-border: var(--p-accent);
}

/* --- Reset and base ------------------------------------------------------ */
*, *::before, *::after { box-sizing: border-box; }

html {
  scroll-behavior: smooth;
  /* Sticky header height, so an in-page anchor is not hidden under it. */
  scroll-padding-top: 88px;
}

body {
  margin: 0;
  background: var(--p-bg);
  color: var(--p-text);
  font: 16px/1.65 var(--p-font);
  -webkit-text-size-adjust: 100%;
}

img, picture, svg, canvas, video { max-width: 100%; }

a { color: var(--p-accent); text-underline-offset: 4px; }
a:hover { text-decoration-thickness: 2px; }

h1, h2, h3, h4, p, ul, ol, dl, figure, pre, table { margin-top: 0; }

h1, h2, h3 { line-height: 1.1; letter-spacing: -0.035em; font-weight: 700; }
h2 { font-size: clamp(28px, 3.4vw, 42px); margin-bottom: 16px; }
h3 { font-size: 21px; letter-spacing: -0.02em; margin-bottom: 10px; }

:focus-visible { outline: 3px solid var(--p-focus); outline-offset: 3px; }

.skip-link {
  position: absolute; top: -100px; left: var(--s-gutter); z-index: 100;
  padding: 12px 18px; border-radius: var(--p-radius-sm);
  background: var(--p-surface); color: var(--p-text);
  border: 1px solid var(--s-control-border);
  text-decoration: none; font-weight: 650;
}
.skip-link:focus { top: 12px; }

/* --- Shared pieces ------------------------------------------------------- */
.container {
  width: 100%; max-width: var(--s-max);
  margin-inline: auto; padding-inline: var(--s-gutter);
}

.muted { color: var(--p-muted); }
.accent { color: var(--p-accent); }
.lead { font-size: clamp(17px, 1.5vw, 20px); color: var(--p-muted); }

.eyebrow {
  display: block;
  font: 600 11px/1.6 var(--p-mono);
  text-transform: uppercase; letter-spacing: 0.18em;
  color: var(--p-accent); margin-bottom: 14px;
}

.row { display: flex; align-items: center; gap: 12px; }
.row--wrap { flex-wrap: wrap; }

.section { padding-block: var(--s-section-y); }
.section--alt { background: var(--p-surface-alt); }
.section + .section--alt, .section--alt + .section { border-top: 1px solid var(--p-border); }

.section-head { max-width: 62ch; margin-bottom: clamp(28px, 3vw, 44px); }
.section-head p:last-child { margin-bottom: 0; }

/* Buttons and links that look like buttons */
.button {
  display: inline-flex; align-items: center; justify-content: center; gap: 10px;
  min-height: 48px; padding: 12px 24px;
  border-radius: 999px;
  border: 1px solid var(--s-control-border);
  background: var(--p-surface); color: var(--p-text);
  font: 650 15px/1.2 var(--p-font); text-decoration: none;
  cursor: pointer;
  transition: background var(--p-duration), color var(--p-duration);
}
.button:hover { background: var(--p-surface-alt); }
.button--primary {
  background: var(--p-accent); color: var(--p-on-accent); border-color: transparent;
}
.button--primary:hover { background: var(--p-emerald-700); color: #ffffff; }
[data-theme="dark"] .button--primary:hover { background: var(--p-mint-300); color: var(--p-on-accent); }
.button .icon { width: 18px; height: 18px; flex: none; }

.icon { width: 24px; height: 24px; display: inline-block; vertical-align: middle; }
.icon-tile {
  width: 46px; height: 46px; flex: none;
  display: grid; place-items: center;
  border-radius: var(--p-radius-sm);
  background: var(--p-surface-alt); color: var(--p-accent);
  margin-bottom: 20px;
}
.section--alt .icon-tile { background: var(--p-surface); }

/* Cards */
.cards {
  display: grid; gap: 20px;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 280px), 1fr));
}
.card {
  padding: clamp(20px, 2.4vw, 30px);
  background: var(--p-surface);
  border: 1px solid var(--p-border);
  border-radius: var(--p-radius-md);
  box-shadow: var(--p-shadow);
}
.card > :last-child { margin-bottom: 0; }
.card p { color: var(--p-muted); font-size: 15px; }
.step-label {
  font: 600 13px/1.4 var(--p-mono); letter-spacing: 0.08em;
  color: var(--p-accent); margin-bottom: 16px;
}

/* A quieter card for callouts that are not part of a grid */
.panel {
  padding: clamp(20px, 2.4vw, 28px);
  background: var(--p-surface);
  border: 1px solid var(--p-border);
  border-left: 4px solid var(--p-accent);
  border-radius: var(--p-radius-md);
}
.panel > :last-child { margin-bottom: 0; }
.panel h3 { margin-bottom: 8px; }

/* Spacing utilities, so section markup does not carry inline styles */
.stack { margin-top: clamp(28px, 3vw, 44px); }
.note { margin: 24px 0 0; }
.unlisted { list-style: none; padding: 0; margin: 0; }

/* A bulleted list of statements, each in its own bordered row */
.bullets { display: grid; gap: 10px; padding: 0; margin: 0; list-style: none; }
/* Absolute marker, not flex: a flex row turns every inline element in the
   sentence (an inline <code>, say) into its own flex item and squeezes it to
   one character per line. */
.bullets li {
  position: relative;
  padding: 14px 18px 14px 42px; border-radius: var(--p-radius-md);
  background: var(--p-surface); border: 1px solid var(--p-border);
  font-size: 15px;
}
.bullets li::before {
  content: ""; position: absolute; left: 20px; top: 22px;
  width: 8px; height: 8px; border-radius: 50%; background: var(--p-accent);
}

/* Plain bulleted prose inside a .panel */
.panel-list { margin: 0; padding-left: 1.25em; display: grid; gap: 10px; color: var(--p-muted); }

/* Code */
.code-block {
  font: 13px/1.9 var(--p-mono);
  background: var(--s-code-bg); color: var(--s-code-fg);
  border: 1px solid var(--s-code-border);
  border-radius: var(--p-radius-md);
  padding: clamp(18px, 2vw, 26px);
  /* Wrap rather than scroll. A clone URL is 62 characters and overflowed its
     card with no scroll affordance, and a command a reader is meant to copy
     must not be half off-screen. Soft wraps add no characters, so a copy of a
     wrapped line is still the command. */
  white-space: pre-wrap; overflow-wrap: anywhere;
}
code { font-family: var(--p-mono); font-size: 0.94em; }
/* Inline code in prose is styled by content.css `.c-code` - one look for the
   whole page. Do not add a second inline-code rule here. */

/* Two-column split */
.split { display: grid; gap: clamp(28px, 4vw, 56px); }
@media (min-width: 62rem) {
  .split { grid-template-columns: repeat(2, minmax(0, 1fr)); align-items: center; }
  .split--wide-left { grid-template-columns: minmax(0, 1.15fr) minmax(0, 1fr); }
}
.split > * > :last-child { margin-bottom: 0; }

/* --- Header ------------------------------------------------------------- */
.site-header {
  position: sticky; top: 0; z-index: 50;
  background: var(--p-bg);
  border-bottom: 1px solid var(--p-border);
}
.site-header__inner {
  display: flex; align-items: center; justify-content: space-between;
  gap: 20px; min-height: 76px;
}
.brand-link { display: inline-flex; align-items: center; text-decoration: none; }
.brand-mark { display: block; width: clamp(150px, 16vw, 196px); height: auto; }
.brand-mark--dark { display: none; }
[data-theme="dark"] .brand-mark--dark { display: block; }
[data-theme="dark"] .brand-mark--light { display: none; }

.site-nav { display: flex; align-items: center; gap: clamp(12px, 2vw, 28px); }
.site-nav__links { display: flex; align-items: center; gap: clamp(12px, 2vw, 26px); }
.site-nav__links a {
  color: var(--p-muted); text-decoration: none; font-size: 15px; white-space: nowrap;
}
.site-nav__links a:hover { color: var(--p-text); text-decoration: underline; }
/* Marks the section you are looking at. An underline drawn out of flow, NOT
   font-weight: 650 - that widened a 400 link by 4.13px, and site.js moves this
   marker while you scroll, so every move reflowed the header. It was the only
   layout shift on the page; CLS is 0 without it. Also a second cue besides
   colour. */
.site-nav__links a { position: relative; }
.site-nav__links a[aria-current] { color: var(--p-accent); }
.site-nav__links a[aria-current]::after { content: ""; position: absolute; left: 0; right: 0; bottom: -7px; height: 2px; background: var(--p-accent); border-radius: 2px; }

/* Reserve the toggle's box so revealing it after hydration shifts nothing. */
.theme-slot { flex: 0 0 46px; height: 46px; display: grid; place-items: center; }
.theme-toggle {
  width: 46px; height: 46px; padding: 0;
  display: grid; place-items: center;
  border-radius: 999px; border: 1px solid var(--s-control-border);
  background: var(--p-surface); color: var(--p-text); cursor: pointer;
}
.theme-toggle:hover { background: var(--p-surface-alt); }
.theme-toggle .icon-moon { display: none; }
[data-theme="dark"] .theme-toggle .icon-sun { display: none; }
[data-theme="dark"] .theme-toggle .icon-moon { display: block; }

@media (max-width: 62rem) {
  /* The in-page nav collapses; every one of its targets is also in the footer
     nav, so nothing becomes unreachable. */
  .site-nav__links { display: none; }
}
@media (max-width: 34rem) {
  /* At 360 the header CTA wrapped to two lines. Drop it - the hero's identical
     Quick Start button is immediately below it. */
  .site-header .button--primary { display: none; }
}

/* --- Hero --------------------------------------------------------------- */
.hero { padding-block: clamp(40px, 6vw, 88px); overflow-x: clip; }
.hero__grid { display: grid; gap: clamp(32px, 5vw, 64px); align-items: center; }
@media (min-width: 62rem) {
  .hero { min-height: min(86vh, 920px); display: grid; align-items: center; }
  .hero__grid { grid-template-columns: minmax(0, 1fr) minmax(0, 1.3fr); }
  /* Run the art out to the viewport edge: its own width grows by the container's
     right gutter plus whatever slack the capped container leaves at this width,
     so the chameleon bleeds off the page instead of sitting in a framed panel.
     Widening the stage rather than negative-margining the container matters -
     .container is width:100% with margin-inline:auto, so a negative margin
     shifts the whole box right and adds a horizontal scrollbar.
     The rule that does it lives with `.hero-stage` below, not here: at equal
     specificity the later declaration wins, and `.hero-stage`'s own
     `width: 100%` is further down the file. */
}

.hero__copy { max-width: 40rem; }
.hero__title { margin: 0 0 24px; display: block; }
.hero__wordmark {
  display: block; width: clamp(230px, 32vw, 430px); height: auto;
  margin-bottom: clamp(14px, 2vw, 22px);
}
.hero__wordmark--dark { display: none; }
[data-theme="dark"] .hero__wordmark--dark { display: block; }
[data-theme="dark"] .hero__wordmark--light { display: none; }
.hero__tagline {
  display: block;
  font-size: clamp(30px, 4.1vw, 56px);
  line-height: 1.06; letter-spacing: -0.04em; font-weight: 700;
}
.hero__pitch { font-size: clamp(17px, 1.6vw, 21px); color: var(--p-muted); margin-bottom: 30px; max-width: 34rem; }
.hero__actions { gap: 14px; }
.hero__meta {
  margin: 26px 0 0; padding: 0; list-style: none;
  display: flex; flex-wrap: wrap; gap: 8px 22px;
  font: 500 13px/1.5 var(--p-mono); color: var(--p-muted);
}
.hero__meta li { display: flex; align-items: center; gap: 8px; }
.hero__meta .icon { width: 16px; height: 16px; color: var(--p-accent); }

/* ===========================================================================
   #hero-stage - THE ANIMATION SLOT.

   This box owns its own height through aspect-ratio, so its single child can
   be swapped for a <canvas>, <svg>, <video> or Lottie container with no
   reflow anywhere on the page. `.hero-stage > *` sizes whatever that child
   turns out to be.
   =========================================================================== */
.hero-stage {
  position: relative;
  width: 100%;
  aspect-ratio: var(--s-stage-ratio);
  overflow: hidden;
  /* No border and no radius: a frame reads the art as a figure beside the page
     rather than as the page you have landed on.

     The mask melts three of the crop's edges into the page. The banner carries
     its own dark vignette, close to --p-bg but not equal to it, so without this
     the stage reads as a visible rectangle. Left, top and bottom fade; the right
     edge stays hard because it bleeds off the viewport anyway.

     Two linear gradients intersected rather than one radial: the box is much
     wider than it is tall, so no single radial reaches the left edge and the
     top edge at the same normalised radius. Where `mask-composite` is
     unsupported the two images default to `add`, which is the union - the fade
     is lost but nothing breaks.

     This is presentation on the stage, not on its contents: an animation put in
     here inherits the same soft edge. Delete it if that is unwanted. */
  -webkit-mask-image:
    linear-gradient(to right, transparent 0, #000 28%),
    linear-gradient(to bottom, transparent 0, #000 15%, #000 85%, transparent 100%);
  -webkit-mask-composite: source-in;
  mask-image:
    linear-gradient(to right, transparent 0, #000 28%),
    linear-gradient(to bottom, transparent 0, #000 15%, #000 85%, transparent 100%);
  mask-composite: intersect;
}
/* Full bleed, in source order after the base `width: 100%` so it actually wins. */
@media (min-width: 62rem) {
  .hero-stage { width: calc(100% + var(--s-bleed) + var(--s-gutter)); }
}
/* Below the two-column breakpoint the stage bleeds both gutters instead. */
@media (max-width: 62rem) {
  .hero-stage { margin-inline: calc(-1 * var(--s-gutter)); width: auto; }
}

.hero-stage > * { display: block; width: 100%; height: 100%; }
/* Banner and eye overlay stack inside the single child. */
.hero-art { position: relative; }
.hero-art > * { position: absolute; inset: 0; width: 100%; height: 100%; }
.hero-art img { display: block; width: 100%; height: 100%; object-fit: cover; object-position: right center; }
/* Theme-correct hero art, keyed on [data-theme] and nothing else.

   The <picture> in the stage carries only the LIGHT art. The dark theme is
   painted as a background on the picture with the <img> hidden. One mechanism,
   no `prefers-color-scheme` anywhere in this file or in the markup, so the art
   can never disagree with the palette:

     light theme (JS on or off, any OS)  visible <img>, light art, no background
     dark theme  (needs JS to set the attribute)  dark background, <img> hidden

   An earlier version branched the <picture> on `prefers-color-scheme` as well,
   which worked but meant two independent branches had to agree. They did - but
   only because a second, symmetric override rule existed to make them, and
   that is a fragile thing to leave behind for whoever swaps this child out.

   Being CSS rather than JS, it is already correct on the first paint. The
   plain url() line is the fallback for engines without image-set() + type().

   Trade: a dark visitor still fetches the light webp for the hidden <img>
   (~20 KB at 1280). It stays because it is the picture's required non-webp
   fallback and, in the light theme, the hero's LCP element. */
.hero-stage__art { background-position: right center; background-size: cover; background-repeat: no-repeat; }

[data-theme="dark"] .hero-stage__art {
  background-image: url("brand/banners/hero-dark-1920.png");
  background-image: image-set(
    url("brand/banners/hero-dark-1920.webp") type("image/webp"),
    url("brand/banners/hero-dark-1920.png") type("image/png"));
}
[data-theme="dark"] .hero-stage__art > img { visibility: hidden; }

/* --- Terminal demo section shell ---------------------------------------- */
/* Everything from .pterm inward is owned by terminal.css. The only thing
   site.css guarantees is the width of the box it sits in - no fixed height, and
   no overflow clipping that could cut off its focus rings.

   WIDTH IS THE CONTRACT HERE, and it is measured, not chosen. The widest
   captured transcript line is 84 columns; at terminal.css's maximum font size
   the character advance is 8.101px, so a line needs 680.5px of usable
   `.pterm-out`. Inside the plain container that box came to 656.1px and the
   transcripts scrolled sideways by 24.4px at every desktop width - including
   1920, where 728px of viewport was going unused because --s-max caps the
   container at 1280.

   So the terminal alone reaches 34px past each gutter: the heading stays aligned
   with every other section and the box gains 68px. Re-measure if terminal.css
   changes its font size or a transcript gets wider.

   A caution: this +68px once coexisted with the block being pasted re-indented,
   adding six columns to every line (whitespace is data inside <pre>). The two
   nearly cancelled - 697.4px of text in a 697px box - so a 0.4px overflow drifted
   in and out of failure and read as a bug in terminal.css. Two defects in
   opposite directions look like one mystery in someone else's file. Below
   the two-column breakpoint the transcripts cannot fit at any width this page
   could give them, and scrolling them is web-terminal's deliberate choice over
   reflowing a table into nonsense. */
.demo-frame { margin-top: clamp(24px, 3vw, 40px); }
@media (min-width: 62rem) {
  .demo-frame { margin-inline: calc(-1 * min(var(--s-gutter), 34px)); }
}

/* --- Screenshot figure -------------------------------------------------- */
.shot { margin: 0; }
.shot > img {
  width: 100%; height: auto;
  border-radius: var(--p-radius-md); border: 1px solid var(--p-border);
}
/* Specificity matters here: `.shot > img` also sets display, so the theme
   switch must match at least as tightly or both screenshots render. */
.shot > .shot--light { display: block; }
.shot > .shot--dark { display: none; }
[data-theme="dark"] .shot > .shot--light { display: none; }
[data-theme="dark"] .shot > .shot--dark { display: block; }
.shot figcaption { margin-top: 14px; font-size: 14px; color: var(--p-muted); }

/* --- Docs chapter list -------------------------------------------------- */
.chapter-list { display: grid; gap: 14px; padding: 0; margin: 0; list-style: none; }
@media (min-width: 48rem) { .chapter-list { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
.chapter {
  display: flex; gap: 16px; align-items: flex-start;
  padding: 20px 22px; text-decoration: none;
  background: var(--p-surface); border: 1px solid var(--p-border);
  border-radius: var(--p-radius-md); color: var(--p-text);
}
.chapter:hover { border-color: var(--s-control-border); background: var(--p-surface-alt); }
.chapter__number { font: 600 13px/1.6 var(--p-mono); color: var(--p-accent); flex: none; }
.chapter__title { display: block; font-weight: 650; margin-bottom: 4px; }
.chapter__summary { display: block; font-size: 14px; color: var(--p-muted); }

/* --- Dark band before the footer --------------------------------------- */
.band { background: var(--s-band-bg); color: var(--s-band-fg); }
.band__inner {
  padding-block: clamp(48px, 6vw, 88px);
  display: grid; gap: 28px; align-items: center;
}
@media (min-width: 62rem) {
  .band__inner { grid-template-columns: minmax(0, 1fr) auto; gap: 48px; }
}
.band h2 { margin-bottom: 12px; }
.band p { color: var(--s-band-muted); margin-bottom: 0; max-width: 54ch; }
.band .eyebrow { color: var(--p-mint-300); }
.band .button { background: var(--s-band-fg); color: var(--p-forest-900); border-color: transparent; }
.band .button:hover { background: var(--p-mint-100); }
.band .button--ghost {
  background: transparent; color: var(--s-band-fg); border-color: var(--p-mint-300);
}
.band .button--ghost:hover { background: rgba(255, 255, 255, 0.12); color: var(--s-band-fg); }

/* --- Footer ------------------------------------------------------------- */
.site-footer { border-top: 1px solid var(--p-border); padding-block: clamp(36px, 4vw, 56px); font-size: 15px; }
.site-footer__grid { display: grid; gap: 32px; }
@media (min-width: 48rem) {
  .site-footer__grid { grid-template-columns: minmax(0, 1.4fr) repeat(2, minmax(0, 1fr)); }
}
.site-footer h2 { font: 600 11px/1.6 var(--p-mono); text-transform: uppercase; letter-spacing: 0.14em; color: var(--p-muted); margin-bottom: 14px; }
.site-footer ul { list-style: none; padding: 0; margin: 0; display: grid; gap: 10px; }
.site-footer a { color: var(--p-text); text-decoration: none; }
.site-footer a:hover { color: var(--p-accent); text-decoration: underline; }
.footer-tagline { margin-top: 16px; max-width: 38ch; }
.site-footer__legal { margin: 32px 0 0; padding-top: 24px; border-top: 1px solid var(--p-border); color: var(--p-muted); font-size: 14px; }
.site-footer__legal p { margin: 0 0 6px; }
.site-footer__legal p:last-child { margin-bottom: 0; }

/* --- Reduced motion ----------------------------------------------------- */
@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;
  }
}
