/* Local page compositions for the Burnside marketing site.
   Kit components come from ui.css. Anything here that a second project needs
   should be promoted into the design-system kit per PATTERNS.md, not copied. */

/* GRE-365 item 9. The brand magenta was chosen on a dark field, where it is 6.01:1. The
   product ships both themes, and on the light field it is 2.76:1 against the cream page and
   3.09:1 on a white card, against WCAG 1.4.3's 4.5:1 -- so accent-coloured TEXT, which is
   mostly links, fails on every light-theme page. Passing comfortably in the theme it was
   picked in is why it survived this long.

   A separate token rather than a darker --ds-accent, deliberately. Text needs 4.5:1;
   borders, tinted badges, underlines and solid fills need 3:1 and already clear it. Redefining
   the accent would darken all of them together and change how the brand reads in light mode,
   for a requirement only the text has. The kit already draws this distinction with
   --ds-accent-solid; this is the same idea one step further, for the one job that needs it.

   Dark restores the bright accent, which is correct there at 6.01:1. Declared on bare :root
   rather than [data-theme="light"] because the attribute is set by JavaScript: before boot
   runs, with JS disabled, or when initTheme throws (Safari with "Block All Cookies" raises
   SecurityError reading localStorage, which is why boot.ts wraps it in safeInit), no attribute
   is set at all. Light has to be the default, not a branch. */
:root { --ds-accent-text: #B81866; }
:root[data-theme="dark"] { --ds-accent-text: var(--ds-accent); }

/* Kit default is var(--ds-accent). See --ds-accent-text above. */
.ds-link { color: var(--ds-accent-text); }

/* GRE-365 item 1. The kit's ui.css sets, for every control on every surface:
       :focus-visible { outline: none; box-shadow: var(--ds-focus-ring); }
   and --ds-focus-ring resolves to a 14%-alpha accent, measured live at 1.16:1 on the
   light page and 1.18:1 on dark against WCAG 2.4.11's 3:1. A keyboard user cannot see
   where they are. Worse, a box-shadow is not painted at all in forced-colors mode, so a
   Windows High Contrast user has no indicator whatsoever.

   An outline is painted in forced-colors (and forced to a system colour there), which is
   why the property changes rather than just the value. --ds-accent-solid is the deeper
   magenta the kit already ships for solid fills; it clears 3:1 on all five backgrounds a
   ring can land on, worst case 3.19:1 on the dark raised card.

   The upstream fix belongs to the design-system repo, which releases separately. Until it
   lands this override is what a keyboard user has. Guarded by www/test/focus-ring.spec.ts,
   which measures the ratio rather than matching the text, and fails the day the kit no longer needs it. */
:focus-visible {
  outline: 3px solid var(--ds-accent-solid);
  outline-offset: 2px;
  box-shadow: none;
}

/* GRE-163 hid .ds-nav .ds-btn below 720px because two CTAs plus the toggle overflowed
   a 375px viewport. GRE-166 leaves a single button; measured at 375px with the hide
   rule removed, document.documentElement.scrollWidth is 360 against a 375 viewport, no
   horizontal scroll, so the rule is deleted rather than kept: mobile visitors keep the
   hosted CTA in the nav.

   GRE-366 item 20 renamed that button from "Start hosted" to "Start free" and re-measured
   at 375: scrollWidth 375, still no horizontal scroll, and the button is 96px wide against
   115px for the label the original figure was taken with. The 360 above is not what a
   re-measure gives today; the property it recorded -- the nav fits without scrolling --
   still holds, and the button only got narrower. */
.ds-nav__brand { flex-shrink: 0; }

/* Hero, centred. .ds-hero already centres text; the first pass overrode that to
   left-align for a left-aligned prompt block, and this pass reverts to the kit's
   default because the composition is now centred like Exa's. GRE-166. */
.site-hero .ds-hero__lede { max-width: 52ch; }
/* .ds-display is a flat 5rem in the kit. The headline is 48 characters and centred, so
   this uses a gentler slope than the first pass and a lower ceiling, which stops a
   centred single line spanning an uncomfortable measure on a wide monitor. */
.site-hero .ds-display { font-size: clamp(2.25rem, 5.5vw, 4rem); text-wrap: balance; }
/* .site-hero__actions previously supplied only margin-top, with no display: flex, so
   the two buttons in #close laid out as centred inline content with a source-whitespace
   gap rather than a real one: at 1440px the gap measured 4.2px, not the token value. The
   markup now also carries the kit's own .ds-hero__actions, which supplies
   display: flex, a real gap and justify-content: center, so .site-hero__actions is kept
   in the markup only for identification and carries no rule here any more. GRE-166. */

/* The kit's .ds-hero__actions carries its own margin-top, but nothing follows it, so the
   note under the button row sat flush on the buttons: 0px at every viewport. It is a
   footnote on those two buttons, so it takes space-4 rather than the space-5 that separates
   the larger blocks around it. GRE-231. */
.site-hero__note { margin-top: var(--ds-space-4); }

.site-hero__alt { margin-top: var(--ds-space-5); }

/* Fact strip: occupies the slot a competitor fills with a customer logo wall.
   Four claims a visitor can verify in about a minute. GRE-163. */
.site-facts { padding: var(--ds-space-5) 0; border-block: 1px solid var(--ds-border); }
.site-facts__list {
  display: flex; flex-wrap: wrap; gap: var(--ds-space-3) var(--ds-space-6);
  margin: 0; padding: 0; list-style: none;
  font-size: var(--ds-text-sm); color: var(--ds-text-muted);
}

.site-prose { max-width: 62ch; }
.site-prose + .site-prose { margin-top: var(--ds-space-4); }
/* The kit resets every margin, so prose sat flush against a following grid with no gap at
   all. There was a rule for prose followed by prose and none for prose followed by anything
   else. Space-6 rather than the space-5 used under a section title: this is a structural
   break into cards, not the gap between a heading and its own paragraph. */
.site-prose + .ds-grid { margin-top: var(--ds-space-6); }
/* .site-prose has no auto margin of its own because most of its uses sit in a left-aligned
   .ds-section, where centring the block would be wrong. #close is the exception: it is a
   .ds-hero, which centres text, and without an auto margin the 62ch box stayed pinned to
   the container's left edge, centring only the text inside it. At 1440px that put the
   paragraph's text 221px off the h2 and the button row's centre. Scoped to .ds-hero so the
   left-aligned uses elsewhere are untouched. GRE-166. */
.ds-hero .site-prose { margin-inline: auto; }

/* Section flow. The kit's reset is `* { margin: 0 }`, so every vertical gap in a composition
   is opt-in and any pair of blocks without a rule renders flush. .site-prose covers its own
   two cases above; these are the remaining pairs the pages actually use.
   Written as adjacent-sibling rules rather than one blanket `.ds-container > * + *`: that
   selector scores (0,2,0) and would outrank the kit's own .ds-hero__lede and
   .ds-hero__actions margins at (0,1,0), quietly replacing 24px with whatever the blanket
   rule said. Explicit pairs cannot do that.
   The values encode what belongs to what. A caption sits close to the thing it captions
   (space-3 down to the code block it introduces) and further from the thing it does not
   (space-5 up to the card grid above it), so the reading order is unambiguous. GRE-231. */
.ds-grid + .ds-help { margin-top: var(--ds-space-5); }
.ds-help + .ds-code { margin-top: var(--ds-space-3); }
.ds-code + .ds-btn { margin-top: var(--ds-space-4); }

/* .ds-card is a plain padded box in the kit and a bare <h3> carries no margin of its own,
   so every card title sat flush on its body copy. space-2 is the value the kit's own
   .ds-card__title uses, so the cards match the kit's spacing intent without also adopting
   its type scale, which would change how the headings look and not just where they sit. GRE-231. */
.ds-card > h3 { margin-bottom: var(--ds-space-2); }

/* Written for /docs, a .ds-prose block since removed; now used by the legal pages, which are
   .ds-prose too. The kit gives its paragraphs a bottom margin and its headings nothing, so the
   h1 sat flush on the paragraph below it. GRE-231. */
.ds-prose :is(h1, h2, h3) { margin-bottom: var(--ds-space-4); }

/* A rendered example of what relay/src/format.ts emits, styled to read as a tracker
   issue. Real markup rather than a screenshot so it stays legible, selectable, and
   correct in dark mode. GRE-163. */
.site-issue {
  border: 1px solid var(--ds-border); border-radius: var(--ds-radius-lg);
  overflow: hidden; margin-block: var(--ds-space-5); max-width: 68ch;
}
.site-issue__bar {
  display: flex; align-items: center; gap: var(--ds-space-3);
  padding: var(--ds-space-3) var(--ds-space-4);
  border-bottom: 1px solid var(--ds-border); background: var(--ds-hover);
}
.site-issue__title { font-weight: 500; }
.site-issue__body { padding: var(--ds-space-4); }
.site-issue__meta { border-collapse: collapse; margin-block: var(--ds-space-4); width: 100%; }
.site-issue__meta th, .site-issue__meta td {
  text-align: left; padding: var(--ds-space-2) var(--ds-space-3);
  border-bottom: 1px solid var(--ds-border); font-size: var(--ds-text-sm);
}
.site-issue__meta th { color: var(--ds-text-muted); font-weight: 400; width: 9rem; }
.site-issue__shot {
  display: block; width: 100%; height: auto;
  border: 1px dashed var(--ds-border); border-radius: var(--ds-radius-sm);
  margin-block: var(--ds-space-3);
}

/* Styled like the dashed placeholder it replaces. The <pre> scrolls inside its own
   container so a long console line cannot widen the page. */
.site-issue__log {
  border: 1px dashed var(--ds-border); border-radius: var(--ds-radius-sm);
  padding: var(--ds-space-4); margin-block: var(--ds-space-3);
  color: var(--ds-text-muted); font-size: var(--ds-text-sm);
}
.site-issue__log summary { cursor: pointer; font-weight: 500; color: var(--ds-text); }
.site-issue__log pre {
  overflow-x: auto; margin-top: var(--ds-space-3); font-family: var(--ds-font-mono); font-size: var(--ds-text-sm);
}

/* Comparison table. Wide content scrolls inside its own container so the page body
   never scrolls horizontally on a narrow viewport. Shared with .site-tiers below
   (the pricing page's own comparison table): both tables' cells share the same base
   look, so that base is written once here rather than twice. What differs between the
   two tables (min-width, and every thead rule) stays with each table instead of being
   forced into this shared block. GRE-168 branch review, minor finding. */
.site-table-wrap { overflow-x: auto; margin-block: var(--ds-space-5); }
.site-compare { border-collapse: collapse; width: 100%; min-width: 34rem; }
.site-compare th, .site-compare td, .site-tiers th, .site-tiers td {
  text-align: left; padding: var(--ds-space-3) var(--ds-space-4);
  border-bottom: 1px solid var(--ds-border); font-size: var(--ds-text-sm);
  vertical-align: top;
}
.site-compare thead th { color: var(--ds-text-muted); font-weight: 500; }
.site-compare tbody th, .site-tiers tbody th { font-weight: 400; }
.site-compare__honest { color: var(--ds-text-muted); }

/* Native <details> rather than a scripted accordion: keyboard and screen reader
   behaviour for free, and boot.ts gains no new responsibility. */
.site-faq details { border-bottom: 1px solid var(--ds-border); }
.site-faq summary {
  cursor: pointer; padding: var(--ds-space-4) 0;
  font-weight: 500; list-style-position: outside;
}
.site-faq details p { padding-bottom: var(--ds-space-4); color: var(--ds-text-muted); max-width: 62ch; }

/* The closing CTA reuses the hero composition, with a rule above it so the page has
   a clear ending rather than trailing off. */
.site-close { border-top: 1px solid var(--ds-border); }

/* Nav, centred links. The kit's .ds-nav is a plain flex row; centring the middle group
   needs the outer children to claim equal space, which is what the two auto margins do.
   Matches Exa and Mintlify, both of which centre their nav links. GRE-166. */
.site-nav { justify-content: center; gap: var(--ds-space-5); }
.site-nav__links { margin-inline: auto; }

/* Below 720px the kit hides .ds-nav__links entirely (the kit's own breakpoint, not a
   local rule), so there is nothing left to centre and centring the remaining two
   children (brand, button) would split the row unevenly across the content box.
   flex-start plus a smaller gap keeps the brand and button flush against the row's
   own edges instead of splitting the difference between them. The row's width was
   last measured against the stacked wordmark (26 x 59.1); the nav now draws the
   short mark (26 x 150.4), about 91px wider, so the row has not been re-measured
   since and no figure from that measurement still applies. GRE-166. */
@media (max-width: 720px) {
  .site-nav { justify-content: flex-start; gap: var(--ds-space-3); }
}

/* The wordmark is an <img> of the outlined master, which carries its own
   prefers-color-scheme block and so inverts without a second asset. Height comes
   from the kit's --ds-brand-nav-h token, not a local rule: this file sets no height
   on the img. The nav draws wordmark-short.svg (viewBox 0 0 4264 737); the footer
   still draws the unsuffixed stacked wordmark.svg (viewBox 0 0 4251 1870), a
   different aspect ratio, so the two are not interchangeable. */
.site-lockup { display: inline-flex; align-items: center; flex-shrink: 0; text-decoration: none; }
/* Nav links carry no underline. The kit's .ds-link underlines by default, which is right
   for links in prose and wrong for navigation. */
.site-nav__link { text-decoration: none; }
.site-nav__link:hover { text-decoration: none; color: var(--ds-text); }

/* Install card. Tabs and the tracker selector are radio inputs switched by :has(), so
   switching needs no JavaScript at all: the card is never briefly inert on a slow
   connection, and labels give keyboard and screen-reader behaviour for free.
   install-card.ts handles only the clipboard, which CSS cannot do. :has() matches
   regardless of where the radios sit in the DOM, so nothing below constrains their
   position relative to the panels. GRE-166, GRE-167. */
.site-ic {
  position: relative; /* contains the absolutely positioned radios and legends below */
  max-width: 640px; margin: var(--ds-space-5) auto 0; text-align: left;
  border: 1px solid var(--ds-border); border-radius: var(--ds-radius-lg);
  overflow: hidden; background: var(--ds-code-bg);
}
/* Visually hidden but focusable, so the labels stay keyboard reachable. Not display:none,
   which would remove them from the tab order and break that. */
.site-ic__radio {
  position: absolute; width: 1px; height: 1px; margin: -1px;
  clip-path: inset(50%); overflow: hidden; white-space: nowrap;
}
.site-ic__bar { display: flex; align-items: stretch; border-bottom: 1px solid rgba(255,255,255,.13); }
.site-ic__spacer { flex: 1; }
/* Neither radio group had a name a screen reader could announce: role="group" plus
   aria-label on a div puts the name on a node that is never focused, so a screen reader
   tabbing through the radios (the actual focusable controls) never hears it. A real
   <fieldset>/<legend> puts the group name where the accessibility tree attaches it to
   each control automatically. Now that :has() (GRE-167) no longer needs the radios and
   panels to be flat siblings, nothing stops nesting the radios inside the fieldset.
   display: contents is deliberately not used on the fieldset: on elements with an
   implicit ARIA role, some browsers drop that role from the accessibility tree under
   display: contents, which is the exact defect being fixed here. So .site-ic__bar is a
   real flex row whose children are the two fieldsets and the spacer, and each fieldset
   is its own flex row internally so the tab/tracker labels still stretch to the bar's
   full height, preserving the narrow-viewport wrap fix above. A <fieldset> also carries
   a default border, margin, padding and a min-width: min-content that would stop it
   shrinking in the flex row; all four are reset below. flex-wrap: wrap is a safety net
   for the narrowest viewports: the tab/tracker labels are white-space: nowrap (see
   below), so at widths where even a single fieldset's own two or three labels do not
   fit side by side, a whole label drops to a second line inside the fieldset rather
   than either overflowing or having its own text wrap mid-phrase. GRE-167. */
.site-ic__group {
  display: flex; align-items: stretch; flex-wrap: wrap;
  border: 0; margin: 0; padding: 0; min-width: 0;
}
/* Same visually-hidden technique as .site-ic__radio: clipped to a 1px box rather than
   display: none or visibility: hidden, either of which would remove the legend from the
   accessibility tree and defeat the point of having it. Absolutely positioned, so it is
   also removed from .site-ic__group's flex flow and cannot affect the labels' layout. */
.site-ic__legend {
  position: absolute; width: 1px; height: 1px; margin: -1px;
  clip-path: inset(50%); overflow: hidden; white-space: nowrap;
}
.site-ic__tab, .site-ic__tracker {
  padding: var(--ds-space-2) var(--ds-space-4); cursor: pointer;
  font-family: var(--ds-font-mono); font-size: var(--ds-text-sm);
  color: rgba(255,255,255,.5);
  white-space: nowrap;
}
.site-ic__tab { letter-spacing: .04em; }
.site-ic__tracker { border-left: 1px solid rgba(255,255,255,.13); }
.site-ic__tab:hover, .site-ic__tracker:hover { color: #fff; }

/* The bar's unwrapped content (two tabs plus three trackers, all nowrap after the
   fieldset restructure) measures 587px. Below that, without this rule, the bar would
   have gone into single-row mode anyway and (before the nowrap rule above existed)
   absorbed the shortfall by wrapping each tab's own text: "Ask your agent" split into
   three lines, the bar ballooned to roughly 80px tall, and align-items: stretch on
   .site-ic__bar then stretched the single-word tracker labels to match, leaving dead
   space beneath them. GRE-166 fixed the equivalent problem below 480px; this closes the
   481-630ish gap it left. GRE-167.
   Measured against a live build, viewport width: bar content stops fitting between
   637px (587px needed vs 587px available, ~0.3px short) and 638px (~0.7px to spare).
   640px is used instead of that razor's edge, both for headroom and because it is also
   .site-ic's own max-width, so nothing above this breakpoint is ever width-constrained
   by the viewport at all. Below it, the bar wraps to two rows: tabs stay on the first,
   and the spacer claiming the full remaining width forces the trackers onto a second
   row of their own, with a hairline above them standing in for the bar's border. At the
   very narrowest widths a fieldset's own two or three nowrap labels can still exceed
   that row's width by themselves; .site-ic__group's own flex-wrap: wrap (above) is what
   keeps that case from overflowing or clipping. */
@media (max-width: 640px) {
  .site-ic__bar { flex-wrap: wrap; }
  .site-ic__spacer { flex-basis: 100%; }
  .site-ic__tracker { border-top: 1px solid rgba(255,255,255,.13); }
}

/* Selected states. :focus-visible on the hidden radio styles its label, so keyboard focus
   is visible even though the input itself is not. :has() lets each rule ask "does this
   card contain a checked/focused radio with this id" without caring where that radio
   sits in the DOM, so nothing here constrains the radios' position relative to the bar
   or the panels. GRE-167. */
.site-ic:has(#ic-agent:checked)  .site-ic__bar [for="ic-agent"],
.site-ic:has(#ic-manual:checked) .site-ic__bar [for="ic-manual"] { color: #fff; box-shadow: inset 0 -2px 0 var(--ds-accent); }
.site-ic:has(#ic-linear:checked) .site-ic__bar [for="ic-linear"],
.site-ic:has(#ic-github:checked) .site-ic__bar [for="ic-github"],
.site-ic:has(#ic-gitlab:checked) .site-ic__bar [for="ic-gitlab"] { color: #fff; }
/* Each radio lights only its own label. A single generic rule using
   .site-ic:has(.site-ic__radio:focus-visible) .site-ic__bar label[for] would match every
   label in the bar, because all five radios share the class and all five labels share
   the parent, so tabbing would outline all five at once and tell a keyboard user
   nothing. */
.site-ic:has(#ic-agent:focus-visible)  .site-ic__bar [for="ic-agent"],
.site-ic:has(#ic-manual:focus-visible) .site-ic__bar [for="ic-manual"],
.site-ic:has(#ic-linear:focus-visible) .site-ic__bar [for="ic-linear"],
.site-ic:has(#ic-github:focus-visible) .site-ic__bar [for="ic-github"],
.site-ic:has(#ic-gitlab:focus-visible) .site-ic__bar [for="ic-gitlab"] { outline: 2px solid var(--ds-accent); outline-offset: -2px; }

/* Panels: hidden by default, revealed by the checked combination. The base rule below is
   what does the hiding, so no rule needs to hide anything explicitly. */
.site-ic__panel { display: none; }
.site-ic:has(#ic-agent:checked):has(#ic-linear:checked) [data-panel="agent-linear"] { display: flex; }
.site-ic:has(#ic-agent:checked):has(#ic-github:checked) [data-panel="agent-github"] { display: flex; }
.site-ic:has(#ic-agent:checked):has(#ic-gitlab:checked) [data-panel="agent-gitlab"] { display: flex; }
.site-ic:has(#ic-manual:checked) [data-panel="manual"] { display: block; }
/* Without :has() every rule in this file that uses it is invalid and dropped, not just
   the panel reveals above: the selected-tab/tracker colour and underline, the
   focus-visible outlines, and the manual-tab tracker dimming all go with it. So the
   degraded state is not just a static Linear prompt, it is one with controls that still
   look and behave as though they do nothing: the tabs remain clickable and toggle their
   radios, but produce no visible change at all. Reveal the default panel so it is a
   static prompt rather than an empty box; that is the only recovery this rule buys.
   :has() has been baseline since late 2023, so real exposure is zero; this is belt and
   braces, not a fully-restored experience. */
@supports not selector(:has(*)) {
  .site-ic__panel[data-panel="agent-linear"] { display: flex; }
}
/* The tracker selector is meaningless on the manual tab, which is tracker-agnostic. Dimmed
   only, not pointer-events: none: the underlying radios were never actually disabled (CSS
   cannot do that), so a keyboard user could always still arrow through the tracker group
   while it looked visually inert. pointer-events: none only added a second, opposite-facing
   gap for mouse users, so it is dropped rather than papered over: the control now stays
   consistently operable for both input methods and merely looks less relevant. GRE-166.
   Because the group stays operable, a mouse user can still change the tracker while this
   dimmed state is showing, and that choice silently persists once they return to the
   agent tab. Dimming every label equally left only the existing :checked → color: #fff
   rule (above) as the cue for which one would still apply, and multiplied by .35 opacity
   that difference was too faint to read at a glance. So the checked label is exempted
   from the dim and stays at full strength: legible at a glance which tracker is still
   selected, rather than a uniformly faint row hiding it. GRE-167. */
.site-ic:has(#ic-manual:checked) .site-ic__bar .site-ic__tracker { opacity: .35; }
.site-ic:has(#ic-manual:checked):has(#ic-linear:checked) .site-ic__bar [for="ic-linear"],
.site-ic:has(#ic-manual:checked):has(#ic-github:checked) .site-ic__bar [for="ic-github"],
.site-ic:has(#ic-manual:checked):has(#ic-gitlab:checked) .site-ic__bar [for="ic-gitlab"] { opacity: 1; }

.site-ic__panel[data-panel^="agent"] {
  align-items: flex-start; gap: var(--ds-space-3); padding: var(--ds-space-4);
  flex-wrap: wrap; /* so .site-ic__status takes its own line. GRE-366 item 24. */
}
.site-ic__panel code {
  flex: 1; font-family: var(--ds-font-mono); font-size: var(--ds-text-sm);
  line-height: 1.65; color: var(--ds-code-fg); white-space: pre-wrap;
}
.site-ic__copy {
  flex-shrink: 0; background: none; border: 0; cursor: pointer; padding: var(--ds-space-1);
  color: rgba(255,255,255,.5); font-size: 1rem; line-height: 1;
}
.site-ic__copy:hover { color: #fff; }

/* GRE-366 item 24. The copy confirmation, and the failure message.
   Empty until it has something to say, and an empty inline element occupies nothing, so the panel
   looks exactly as it did until the button is pressed. `flex-basis: 100%` puts it on its own line
   rather than squeezing the prompt: "Copied" would fit beside the button, and the failure sentence
   would not, and having the two land in different places is worse than giving both a line. */
.site-ic__status {
  flex-basis: 100%; font-size: var(--ds-text-sm); line-height: 1.6;
  color: rgba(255,255,255,.62);
}
.site-ic__status:empty { display: none; }

.site-ic__manual { padding: var(--ds-space-4); color: var(--ds-code-fg); }
.site-ic__manual p { font-size: var(--ds-text-sm); color: rgba(255,255,255,.62); margin: 0 0 var(--ds-space-3); }
.site-ic__manual ol { margin: 0 0 var(--ds-space-3); padding-left: 1.4rem; }
.site-ic__manual li { font-size: var(--ds-text-sm); line-height: 1.9; }
.site-ic__manual code { font-size: var(--ds-text-sm); }
.site-ic__manual a { color: var(--ds-accent-text); }

/* Pricing tiers, on their own page. Scoped to a class rather than a section id: the kit's
   .ds-card is a plain block, so each action landed wherever its own card's text ended and
   the three sat up to 110px apart; a price grid is read across its actions. align-self
   keeps them intrinsically sized, since a column flex would otherwise stretch them to the
   full card width, which is a different design decision than this one. GRE-168.
   The column carries a gap rather than leaving each child to supply its own margin: a flex
   container sidesteps the kit's `* { margin: 0 }` problem entirely, because one gap is a
   floor under every pair at once, so a row added to a card later cannot arrive flush.
   Without it the name, the price and the description all sat on each other at 0px.
   The slack is absorbed by the body copy rather than by an auto margin on the action. Both
   bottom-align the actions across the row, but `margin-top: auto` only ever leaves what is
   left over, so the action in the card that SETS the row height got no clearance at all
   beyond the gap: 12px on Pro against 21px on Free, side by side. Growing the second-to-last
   child instead lets the action keep a stated margin, so every card clears its copy by the
   same 16px however tall the row gets. GRE-231. */
.site-tier { display: flex; flex-direction: column; gap: var(--ds-space-2); }
.site-tier > :nth-last-child(2) { flex: 1 1 auto; }
.site-tier .ds-btn { margin-top: var(--ds-space-2); align-self: flex-start; }
/* The description is the one child that starts a new thought rather than continuing the
   price cluster above it, so it takes the gap plus space-2: 16px against the cluster's 8px.
   :not([class]) is what distinguishes it, since every other <p> in a card is classed. GRE-231. */
.site-tier > p:not([class]) { margin-top: var(--ds-space-2); }

/* Card name. Promoted from <h3> to <h2> so the page's heading outline does not skip a
   level (GRE-168 branch review, finding I3): on the built page the first <h2> follows
   three <h3>s, which reads 1, 3, 3, 3, 2 rather than 1, 2, 2, 2, 2. Each tier is a
   top-level thing on a page about tiers, so promoting the element is the honest fix.
   The kit has no .ds-h3, and a bare heading carries no rule of its own anywhere in this
   file or the kit, so a bare <h3> rendered at the browser's UA default: 1.17em, 700,
   inheriting this page's sans body font and 1.5 line-height. This class pins exactly
   that size and weight so the promotion changes the outline, not the rendered card,
   confirmed against the built page in a browser (18.72px, both before and after). */
.site-tier__name { font-size: 1.17em; font-weight: 700; }

/* The page's own title, not a section heading, so it takes display type at a size that does
   not compete with the landing page's hero. #tiers .ds-display rather than a second class of
   equal specificity to .ds-display (0,1,0 either way): line 31 above wins the same contest
   with .site-hero .ds-display, an ancestor-scoped selector that beats .ds-display regardless
   of which stylesheet loads last. .site-price-title read right only because styles.css happens
   to load after ui.css; this does not depend on load order. GRE-168 branch review, minor
   finding. */
#tiers .ds-display { font-size: clamp(2rem, 4vw, 3rem); margin-bottom: var(--ds-space-4); text-align: center; }

/* Tier comparison. Reuses .site-table-wrap for the scroll container, so the page body never
   scrolls horizontally on a narrow viewport. The column widths are even rather than
   auto-sized, which keeps the Pro and Hosted columns visibly parallel: they hold identical
   values on every capability row and that is the table's main point. GRE-168.
   The base th/td look and the tbody font-weight are shared with .site-compare above; only
   what differs stays here: this table's own min-width and every thead rule. */
.site-tiers { border-collapse: collapse; width: 100%; min-width: 40rem; }
.site-tiers thead th { font-weight: 500; }
.site-tiers thead tr:first-child th {
  color: var(--ds-text-muted); font-family: var(--ds-font-mono);
  font-size: var(--ds-text-sm); letter-spacing: .06em; text-transform: uppercase;
}
.site-tiers__group th {
  font-weight: 500; padding-top: var(--ds-space-5);
  color: var(--ds-text); border-bottom-color: var(--ds-text-muted);
}
.site-tiers td:nth-child(n+2), .site-tiers thead th:nth-child(n+2) { width: 22%; }

/* Pricing deployment bar (GRE-170). Two links, not tabs: each deployment is its own page
   so the URL is shareable and neither page ships the other's markup. The active state
   hangs off aria-current rather than a class, so the styling cannot drift out of step
   with what a screen reader announces. */
/* Asymmetric on purpose: the bar belongs to the cards it switches, not to the paragraph
   above it, so it sits space-5 clear of the prose and space-4 from the grid it controls.
   It had no margin-top at all, which put it flush against the intro copy. GRE-231. */
.site-pt {
  display: flex; gap: var(--ds-space-1);
  margin-block: var(--ds-space-5) var(--ds-space-4);
  border-bottom: 1px solid var(--ds-hairline);
}
/* GRE-365 item 9, two defects in these four lines.
   --ds-ink-muted is the DARK-field muted grey: it is the value --ds-text-muted resolves to
   under [data-theme="dark"], and it is 3.12:1 on the cream page against 4.5:1. Using the
   theme-aware --ds-text-muted instead gives 4.69:1 in light and the identical grey in dark,
   so this reads correctly in both rather than in neither.
   --ds-fg was never a token: not in the kit, not here, not anywhere. A bare var() naming
   nothing resolves to the guaranteed-invalid value, so `color` became `unset` and inherited.
   Both the hover and the aria-current colour were silently doing nothing, which left the
   "you are here" state on this bar carried by its 2px underline alone. */
.site-pt__tab {
  padding: var(--ds-space-2) var(--ds-space-4);
  color: var(--ds-text-muted); text-decoration: none;
  border-bottom: 2px solid transparent; margin-bottom: -1px;
}
.site-pt__tab span { opacity: .7; font-size: .875em; }
.site-pt__tab:hover { color: var(--ds-text); }
.site-pt__tab[aria-current="page"] { color: var(--ds-text); border-bottom-color: var(--ds-accent); }

/* Footer. Replaces the flat row of seven inline links that GRE-231 had only just given a
   real gap to; this supersedes that rule, which turned .ds-footer .ds-container into a flex
   row and would now put the columns and the baseline side by side. GRE-232. */
.site-foot { padding: var(--ds-space-8) 0 var(--ds-space-5); }
/* Five tuned tracks, kept local: the ratios are fitted to this site's five
   specific groups and to the Compare column's anchor text, which makes them
   content rather than structure. The kit ships auto-fit so any group count
   works; this overrides it for the shape this footer actually has. */
.ds-footer__cols { grid-template-columns: 1.3fr 1fr 1fr .8fr 1.2fr; }

/* Five tracks stop fitting before the container does, because the Compare links are the
   widest text in the row. Below the first breakpoint the brand block takes a row of its own
   and the four groups become a 2x2; they stay two-up below that rather than stacking,
   because a single column of nineteen links makes the footer taller than several of the
   pages it sits under.
   Measured in a real browser, not assumed: the 1.3fr 1fr 1fr .8fr 1.2fr row holds with no
   wrapped link and no page overflow all the way down to 1000px, so 999px is a safe cutoff
   for the switch to 2 columns. At 820px and 375px the 2x2 holds with no page overflow;
   Compare's anchor text wraps inside its own cell at 375px, which the brief allows. The
   460px gap step was checked at 430px and 470px on either side of it. */
@media (max-width: 999px) {
  .ds-footer__cols { grid-template-columns: repeat(2, 1fr); }
  .ds-footer__id { grid-column: 1 / -1; max-width: 46ch; }
}
@media (max-width: 460px) {
  .ds-footer__cols { gap: var(--ds-space-5); }
}
