/* =============================================================================
   cyber.senuaai.com -- THE SITE LAYER

   Loads after /css/senua.css and adds ONLY what this site needs and the design
   system does not have. It is 200 lines where it used to be 700, and the 500
   that went were not deleted: they were a SECOND copy of the design system.

   WHAT WAS HERE, and why it had to go. This file defined its own .badge, its
   own .brand, its own .card treatment, its own .hero (as .page-hero, with
   rgba(8,9,11,.97) written out four times -- raw values, in the file whose own
   header rule said "not one raw value"), its own .metric (as .stat and as
   .metric__n/__l/__src), its own .notice modifiers, its own .table-wrap, its
   own masthead and its own footer. Every one of those names also exists in the
   design system, and this file loaded second, so the site was reading this
   copy. The README said "there is exactly one design system here" while that
   was true. It is true now.

   The stylesheet above is vendored WHOLE by scripts/vendor-design-system.sh,
   364 KB of it, not a 39 KB hand-trimmed subset with this file filling the
   gaps. If something in it is wrong, it gets fixed there, where every Senua
   property gets the fix.

   THE RULE, unchanged and now actually kept: not one raw value below. Every
   length, colour, size and duration is a token from the design system.
   ============================================================================= */


/* --- the hero's photograph, accent and framing ------------------------------
   The design system's .hero takes its image from --hero-img, its grade from
   --hero-accent and its focal point from --hero-pos, and says a consuming page
   sets them in its own stylesheet. It cannot be an inline style: this site
   bans the style attribute outright and the gate checks for it.

   So the partials carry data-hero, data-accent and data-pos, and the value is
   selected here. That is a closed set -- a build that emits a value with no
   rule renders a hero with no photograph, which is visible immediately rather
   than silently wrong. */
[data-hero] { --hero-img: none; }
[data-hero="/assets/hero/home.jpg"]    { --hero-img: url("/assets/hero/home.jpg"); }
[data-hero="/assets/hero/shield.jpg"]  { --hero-img: url("/assets/hero/shield.jpg"); }
[data-hero="/assets/hero/pulse.jpg"]   { --hero-img: url("/assets/hero/pulse.jpg"); }
[data-hero="/assets/hero/discern.jpg"] { --hero-img: url("/assets/hero/discern.jpg"); }
[data-hero="/assets/hero/vitals.jpg"]  { --hero-img: url("/assets/hero/vitals.jpg"); }
[data-hero="/assets/hero/pricing.jpg"] { --hero-img: url("/assets/hero/pricing.jpg"); }
[data-hero="/assets/hero/docs.jpg"]    { --hero-img: url("/assets/hero/docs.jpg"); }
[data-hero="/assets/hero/access.jpg"]  { --hero-img: url("/assets/hero/access.jpg"); }
[data-hero="/assets/hero/benchmarking.jpg"] { --hero-img: url("/assets/hero/benchmarking.jpg"); }

[data-accent="violet"] { --hero-accent: var(--brand-violet); }
[data-accent="cyan"]   { --hero-accent: var(--brand-cyan); }
[data-accent="good"]   { --hero-accent: var(--support-success); }

[data-pos="70% 45%"] { --hero-pos: 70% 45%; }
[data-pos="68% 50%"] { --hero-pos: 68% 50%; }
[data-pos="72% 45%"] { --hero-pos: 72% 45%; }
[data-pos="70% 50%"] { --hero-pos: 70% 50%; }
[data-pos="74% 50%"] { --hero-pos: 74% 50%; }
[data-pos="70% 42%"] { --hero-pos: 70% 42%; }
[data-pos="68% 45%"] { --hero-pos: 68% 45%; }
[data-pos="72% 50%"] { --hero-pos: 72% 50%; }

/* A shorter hero for an interior page, where the photograph is a band rather
   than the first screen. The system's min-height is a clamp; this replaces the
   whole clamp rather than adding a second one beside it. */
.hero--tight { min-height: clamp(var(--sp-13), 26vw, calc(var(--sp-13) + var(--sp-12))); }


/* THE PRODUCTS MENU IS THE DESIGN SYSTEM'S, and there is nothing here for it.
   A local .nav-menu was written at this point on the belief that the system had
   no masthead disclosure of destinations -- its .overflow-menu is a menu of
   ACTIONS whose items are buttons, deliberately, and these are links. The
   system does have one: .nav__has-menu and .nav__menu, which opens on :hover
   AND :focus-within so it is keyboard-operable with no script. It was filed
   under Patterns rather than Navigation, which is the whole reason looking for
   it failed. It has since been moved, and this file is thirty lines shorter for
   it. See /navigation/dropdown-menu/. */

/* --- a pricing plan ---------------------------------------------------------
   A card with a price, a feature list and an action pinned to its foot, in a
   row of cards that have to line up whatever their lists do. The design system
   has the card; the price, the list marker and the pinned foot are this site's.
   .plan carries .card in the markup and adds only what is its own. */
.plan { display: flex; flex-direction: column; }
.plan__name {
  margin: 0 0 var(--sp-04);
  font-size: var(--ts-04); font-weight: 600;
  letter-spacing: var(--tr-tight); color: var(--text-primary);
}
.plan__price {
  font-size: var(--ts-09); font-weight: 600;
  line-height: var(--lh-hero); letter-spacing: var(--tr-display);
  color: var(--text-primary); font-variant-numeric: tabular-nums;
}
.plan__period {
  display: block; margin-block-start: var(--sp-03);
  font-size: var(--ts-01); color: var(--text-helper);
}
.plan__list {
  flex: 1 1 auto; margin: var(--sp-06) 0; padding: 0; list-style: none;
  font-size: var(--ts-02); color: var(--text-secondary);
}
.plan__list li {
  position: relative; margin-block-end: var(--sp-04);
  padding-inline-start: var(--sp-06);
}
/* A hairline rather than a tick glyph: a pictographic bullet is a character a
   screen reader reads out, and this list is already a list. */
.plan__list li::before {
  content: ""; position: absolute; inset-inline-start: 0; inset-block-start: 0.55em;
  inline-size: var(--sp-03); block-size: var(--border-w);
  background: var(--text-disabled);
}
.plan__cta { margin-block-start: auto; }
/* INSIDE A GRID THE LIST HAS NO MARGIN OF ITS OWN. The margin above exists for
   the vertical plan card, where the list sits between the price and the action.
   The wide plan puts three of these lists in a grid that already supplies a
   gap, so the two added up: 48px of margin on top of a 32px gap, measured as
   80px of nothing between two lists on a phone. */
.plan--wide .plan__list { margin-block: 0; }
/* The one plan being pointed at. The border is not the only signal -- the
   markup carries a badge saying which it is. */
.plan--featured { border-color: var(--accent); }


/* --- a product tile ---------------------------------------------------------
   A card that is entirely a link, so the whole tile is the target. The card
   and the wrapper-link contract are the design system's (.card + .link--block);
   this adds the displacement line and the pinned "go" row. */
.prod__displaces {
  margin: 0 0 var(--sp-04);
  font-family: var(--font-mono); font-size: var(--ts-01);
  color: var(--text-helper);
}
.prod__go {
  margin-block-start: auto; padding-block-start: var(--sp-05);
  font-size: var(--ts-02); color: var(--accent-text);
}


/* --- the rest ---------------------------------------------------------------
   Small things with no equivalent in the system. */

/* A band that asks for the one action, between two sections of argument. */
.cta-band {
  padding-block: var(--sp-11);
  background: var(--layer-01);
  border-block: var(--border-w) solid var(--border-subtle);
}

/* THE STEP LABEL. It says "Step one", not "1" -- so it is a label, and it was
   written as a 40px square. Two words in a fixed square wrap and overflow it,
   which is what shipped: "Step" on one line and "one" on the next, both
   hanging outside the box. A label is set like the system's eyebrow, because
   that is what it is. */
.step__n {
  display: block;
  margin: 0 0 var(--sp-04);
  font-family: var(--font-mono);
  font-size: var(--ts-01);
  letter-spacing: var(--tr-label);
  text-transform: uppercase;
  color: var(--accent-text);
}

/* A mark in a square, for a section that leads with an icon.

   THE HEADING UNDER IT KEEPS NO TOP MARGIN. A chip is part of the heading it
   introduces, not a block before it: with both margins in play the mark sat
   96px above its own title and read as belonging to the paragraph above
   instead. Measured on the Shield page's three-up explanation. */
.icon-chip {
  display: inline-flex; align-items: center; justify-content: center;
  inline-size: var(--sp-08); block-size: var(--sp-08);
  margin-block-end: var(--sp-05);
  background: var(--layer-03); color: var(--text-helper);
}
.icon-chip + :is(h2, h3, h4) { margin-block-start: 0; }

/* The required marker beside a field label. aria-hidden in the markup, because
   the input already carries `required` and a screen reader announces it. */
.req { color: var(--support-error); }

/* --- a definition list used as key and value ----------------------------------
   The system's .deflist stacks the value UNDER the term, which is right when
   the value is a sentence -- "Source" above "auth.log -- app-prod-03" in a
   sample alert -- and wrong when it is an amount. On the access page eight
   prices took 600px of an otherwise empty column: sixteen short lines, each
   pair 24px from the next, in a list whose longest value is four words. Same
   component, one row per pair, the amount on the right where a column of
   amounts can be scanned. Recorded in the design-system findings note. */
/* No column-gap: the gap is a hole the row's hairline cannot cross, and it
   drew as a break in the middle of every rule. The space between term and
   amount is padding on the cells, which the border runs behind. */
/* THE TERM TAKES WHAT IT NEEDS AND THE VALUE WRAPS, not the other way round.
   With `minmax(0,1fr) auto` the value's max-content width won and the term
   column collapsed: in a 300px card at 412px wide the product names broke
   letter by letter -- "Puls / e / Free", "Cybe / r / Unlimite / d" -- because
   the base layer gives dt `overflow-wrap: break-word`. The term is a short
   name, so it sizes to its content and never breaks; the amount beside it is
   the part with room to reflow. */
.deflist--rows { display: grid; grid-template-columns: max-content minmax(0, 1fr); }
.deflist--rows > dt,
.deflist--rows > dd { margin: 0; padding-block: var(--sp-03); }
.deflist--rows > dt {
  padding-inline-end: var(--sp-05);
  white-space: nowrap; overflow-wrap: normal;
}
.deflist--rows > dd { text-align: end; color: var(--text-secondary); max-inline-size: none; }
/* A hairline per row, so the eye can carry a term across to its amount. The
   first row has the heading above it and does not need one. */
.deflist--rows > dt:not(:first-of-type),
.deflist--rows > dt:not(:first-of-type) + dd {
  border-block-start: var(--border-w) solid var(--border-subtle);
}

/* The sign-in and sign-up column: one narrow measure, centred. */
.authcol { max-inline-size: calc(var(--sp-13) * 3); }

/* A form's live result line. The colour is set by the state class the script
   adds; both states also change the WORDS, which is what carries the meaning. */
.form__status { margin-block-start: var(--sp-05); font-size: var(--ts-02); }
.form__status--ok    { color: var(--support-success); }
.form__status--error { color: var(--support-error); }

/* A row of things on one line that wraps. Not a grid: the items size
   themselves and the row is as long as it is. */
.row { display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-05); }
.row > * { min-inline-size: 0; }
.row--between { justify-content: space-between; }
.row--top { align-items: flex-start; }

/* A column of things with one gap between them. */
.stack { display: grid; gap: var(--sp-05); }
.stack > * { min-inline-size: 0; }

/* A measure narrower than the container, for a band of copy that is read
   rather than scanned.

   A NESTED ONE CLEARS WHAT IT FOLLOWS. `.container.narrow` inside another
   container, after a grid of cards, had no margin at all -- measured landing on
   the exact pixel the grid ended, so a notice read as part of the last card
   rather than as a statement about all of them. A container at the top of its
   section still has the section's own padding above it, so only the nested
   case needs this. */
.narrow { max-inline-size: calc(var(--sp-13) * 5); margin-inline: auto; }
/* A NESTED NARROW COLUMN LINES UP WITH WHAT IS AROUND IT. `.narrow` centres
   itself, which is right for a band that is the whole section -- a call to
   action, a sign-in column. Nested inside a full-width container it centred a
   notice among left-aligned headings, tables and copy, and a block that starts
   256px further in than everything above it reads as belonging to something
   else. Standalone narrow containers still centre; this is only the nested
   case, where there is a gutter to line up with. */
.container .container.narrow {
  margin-block-start: var(--sp-09);
  margin-inline: 0;
  padding-inline: 0;
}
/* ONE LEFT EDGE DOWN THE PAGE. `.narrow` centres the BOX, which put a section
   of read-me copy 220px right of the section above it: on the home page
   "Flat, published, in Australian dollars." starts at the container's left edge
   and "Built for the organisations SaaS cannot serve." started a fifth of the
   way across, so the eye loses the line it has been following. The measure is
   still capped -- nobody reads a 1248px line -- but it is capped on the
   CONTENT, with the box left where every other section's box is. The closing
   call-to-action band keeps the centring: it is a different shape on purpose,
   and the reader is meant to stop there. */
section:not(.cta-band) > .container.narrow { max-inline-size: var(--container); }
/* Components that cap themselves keep their own width, so a prose notice is the
   same width wherever it sits: some sections put it straight in a narrow
   container and some nest that container inside a full one, and the two were
   rendering the same component at 800px and 688px on the same page. */
section:not(.cta-band) > .container.narrow > *:not(.notice, .evidence) {
  max-inline-size: calc(var(--sp-13) * 5);
}

/* The heading block at the top of a section. Every section uses it: eyebrow,
   heading, lede, one wrapper, one gap below. Thirty sections were writing the
   three elements bare instead, which meant the space under a section intro was
   whatever the last element's own margin happened to be -- and two of them set
   the intro in `.muted narrow`, which centres, so the copy started 256px right
   of the heading it belonged to. */
.section-head { margin-block-end: var(--sp-08); }

/* --- prose blocks in a wide container ----------------------------------------
   A SURFACE SHOULD BE THE SIZE OF WHAT IS IN IT. The system caps `.notice p` at
   the measure, which is right -- nobody reads a 1248px line -- but it leaves the
   BOX at whatever width its container gives it. A statement notice in a
   full-width container therefore drew a 1248px panel with 640px of text in the
   left half and nothing in the right. Cap the box the way its text is capped.
   Notices that hold a table or a grid are laying something out rather than
   saying something, and keep the full width. */
:is(.container, .narrow) > .notice:not(:has(:is(table, .table-wrap, .cols-2, .cols-3, .cols-4, .metrics))) {
  max-inline-size: calc(var(--measure) + var(--sp-06) * 2);
}
/* The same for an evidence frame that holds a terminal sample: the sample is
   about 280px of fixed-pitch output and the note under it is capped at the
   measure, so a full-width frame drew a 1248px panel two thirds empty. */
.container > .evidence { max-inline-size: calc(var(--measure) + var(--sp-06) * 2); }
/* TWO PARAGRAPHS IN A NOTICE ARE TWO PARAGRAPHS. `.notice p` is `margin: 0`, so
   a notice making two points ran them together into one block with no break at
   all -- on the pricing page, two different things we do not claim read as one.
   Recorded in the design-system findings note. */
.notice p + p { margin-block-start: var(--sp-04); }

/* SOURCE LINES ON ONE BASELINE. `.metrics` is a grid of independent blocks, so
   each metric's source sits directly under its own label -- and the labels are
   not the same number of lines. Four figures therefore had their conditions at
   four different heights, which reads as four unrelated blocks rather than one
   band. Making the metric a column and pushing the source down puts every
   source line on the same baseline, whatever the label above it did. Recorded
   in the design-system findings note. */
.metric { display: flex; flex-direction: column; }
.metric__source { margin-block-start: auto; padding-block-start: var(--sp-03); }

/* A table that ends a card already has the card's footer rule under it; its own
   bottom margin put a second, invisible one there and left a band of nothing. */
.card .table-wrap:has(+ .card__foot) { margin-block-end: 0; }

/* A paragraph directly after a block component is its source line or its
   footnote, not the next section: it takes a smaller step and the measure,
   because it is read rather than scanned. The rule that says so is with the
   rest of the stacking decisions, below. */


/* --- utilities ---------------------------------------------------------------
   The small things a page needs that are not components. Each is here because
   the markup uses it and the design system has no equivalent; several of them
   ARE gaps in the system rather than site concerns, and are named as such:
   a helper-coloured run of text and a card with no surface are not decisions
   about this site.

   RECORDED AS DESIGN-SYSTEM GAPS, to be closed there rather than grown here:
     .muted        a run of text at the helper role. The system has the token
                   and no utility, so every consuming site writes this line.
     .card--plain  a card's LAYOUT with no surface, border or padding -- what a
                   form or a filter panel wants. The system has .card and no
                   way to ask for its box without its skin.
     .card__head   a card's title row, with something at each end.
     .card__foot   a card's action row, ruled off and pinned to the bottom.
   ============================================================================= */
.muted { color: var(--text-helper); }
.faint { color: var(--text-disabled); }
/* Tabular figures outside a table. Inside one the system's .table .num already
   does this and also aligns the column to the right. */
.num { font-variant-numeric: tabular-nums; }
.nowrap { white-space: nowrap; }
.mt-0 { margin-block-start: 0; }
.block { display: block; }
.ok { color: var(--support-success); }
.accent { color: var(--accent-text); }

/* A section with less air than the default, for a run of short bands. */
.section--slim { padding-block: var(--sp-09); }
.section--slim + .section--slim { padding-block-start: 0; }

/* A card's box without its surface, and the two rows a card can carry. */
/* A CARD'S BOX WITHOUT ITS SURFACE -- and without its space-filling either.
   .card is a flex column whose last child takes the free space, which is what
   makes a row of cards end level. A card--plain is not in a row: it is a
   container used for its layout alone, and inheriting `margin-top: auto` on
   its last child opened 189px of nothing between a heading and the table under
   it, measured on the home page. */
.card--plain {
  background: transparent; border-color: transparent; padding: 0;
}
.card--plain > :last-child { margin-block-start: 0; }
/* A card is a flex column, so a child with no width of its own is stretched to
   the card. That is right for a field and wrong for a button: .btn--block is
   how the system asks for a full-width button, so one that has not asked for it
   must not be given it. */
.card > .btn:not(.btn--block) { align-self: start; }
.card__head {
  display: flex; align-items: baseline; justify-content: space-between;
  /* IT WRAPS, because a heading and a badge do not always fit on one line. At
     412px the cost-of-ownership card's badge ran 26px past the card's own
     padding box -- a flex row with no wrap does not shrink a nowrap badge, it
     lets it out the side. Measured, not guessed. */
  flex-wrap: wrap;
  gap: var(--sp-05); margin-block-end: var(--sp-05);
}
.card__foot {
  margin-block-start: var(--sp-06); padding-block-start: var(--sp-05);
  border-block-start: var(--border-w) solid var(--border-subtle);
}

/* A product tile: a card that is entirely a link, so the whole tile is the
   target. The card and the wrapper-link contract are the system's. */
.prod { display: flex; flex-direction: column; }
.prod > :last-child { margin-block-start: auto; }

/* The one thing in a row being pointed at. The border is never the only
   signal -- the markup carries a badge that says which it is. */
.is-featured { border-color: var(--accent); }

/* The live dot beside a line of evidence. */
.evidence__dot {
  display: inline-block; inline-size: var(--sp-03); block-size: var(--sp-03);
  margin-inline-end: var(--sp-03); border-radius: var(--r-pill);
  background: var(--support-success);
}

/* A blocked verdict in a line of evidence output, beside .ok for an allowed
   one. Both are inside a <pre> of real output, so the colour agrees with a
   WORD that is already there -- ALLOW or BLOCK -- and is never the signal. */
.blk { color: var(--support-error); }

/* The price column of a plan row, set against the name on the other side. */
.right { text-align: right; }

/* A PLAN THAT SPANS ITS GRID: the featured product, as wide as the four beside
   it are together. The design system ships no span classes deliberately -- its
   grid-spans page says a page that uses the grid writes its own and owns the
   collapse rules with them -- so this is ours. Below the medium breakpoint the
   grid is one column and the span is a no-op, which is the collapse. */
.plan--wide { grid-column: 1 / -1; }

/* --- a claim chip -------------------------------------------------------------
   A SHORT VALUE CLAIM, in a row of them: "no rules to tune", "runs on your
   hardware". These were marked up as .badge, which is the design system's
   STATUS component -- its own page says a badge carries a status in a word,
   and "flat price, no attack-time spike" is not a status. A component used for
   the wrong meaning still renders; it just stops meaning anything, and the next
   person to read a badge on this site cannot tell a claim from a state.

   RECORDED AS A DESIGN-SYSTEM GAP: a marketing claim chip is a thing every
   product site has and the system has no component for. .tag is for a filter
   value and .badge is for a status; neither is this. */
.claims {
  display: flex; flex-wrap: wrap; gap: var(--sp-04);
  margin: var(--sp-09) 0 0; padding: 0; list-style: none;
}
.claim {
  padding: var(--sp-03) var(--sp-05);
  border: var(--border-w) solid var(--border-subtle);
  color: var(--text-secondary);
  font-size: var(--ts-02);
}

/* --- space between stacked components -----------------------------------------
   CONSECUTIVE BLOCKS INSIDE A CONTAINER CLEAR EACH OTHER, and until this rule
   they did not. The design system's components carry no outer margin, and that
   is right: the space BETWEEN two components is a decision belonging to the
   layout that puts them together, not to either component. This site's layout
   never made the decision, so a notice after a grid, a card after a row of
   metrics and a form after a card each landed on the exact pixel the one before
   it ended -- measured eighteen times across six pages, at both widths. Two
   bordered boxes touching read as one box with a line through it.

   It is a pair selector rather than a margin on each component, because the
   space is a property of the PAIR: the first and last in a stack still sit
   against the section's own padding, which is what that padding is for.

   .notice + .notice is excluded and keeps the tighter step the design system
   gives it -- a run of notices is one argument in parts, not separate blocks. */
.container > :is(.card, .cols-2, .cols-3, .cols-4, .metrics, .notice, .table-wrap, .row, .claims,
                 .evidence, .btn-group, .deploy, .container, form, article, p) +
             :is(.card, .cols-2, .cols-3, .cols-4, .metrics, .notice, .table-wrap, .row, .claims,
                 .evidence, .btn-group, .deploy, .container, form, article) {
  margin-block-start: var(--sp-08);
}
.container > .notice + .notice { margin-block-start: var(--sp-05); }
/* The pair rule reads left to right, so the closing paragraph of a section --
   a source line, a caveat -- takes the smaller step from the block above it and
   gives the full one to whatever block comes next. Three pairs were landing on
   zero before the list above named them: a button group under a grid, an
   evidence frame under a metric band, and a nested narrow container followed by
   its own footnote. */
.container > :is(.metrics, .cols-2, .cols-3, .cols-4, .table-wrap, .card, .claims, .evidence,
                 .deploy, .container) + p {
  margin-block-start: var(--sp-06);
  max-inline-size: var(--measure);
}

/* The same decision, three places the stack is not a direct child of the
   container: inside a plan card, inside an unclassed wrapper on the access
   page, and after a field hint on the sign-in page. Same rule, same reason --
   the space belongs to the pair. */
.plan > .row + :is(.cols-2, .cols-3, .cols-4) { margin-block-start: var(--sp-07); }
.authcol > * + :is(.notice, .card) { margin-block-start: var(--sp-08); }
:is(form, .card) + :is(.card, .notice) { margin-block-start: var(--sp-08); }

/* THE SAME DECISION ONE LEVEL DOWN, which is where it was still missing. The
   container rule above reaches a container's own children and stops, so inside
   a card, a form or a plan nothing owned the space between two blocks: the note
   under the deployment diagram, the note under the wide plan's feature lists,
   the reassurance line under every submit button and the row of links under
   sign-in all landed on ZERO. Twenty-six pairs across nine pages, identical at
   1440, 820 and 412 -- it was never a responsive problem, it was a missing rule.

   Three pairs keep their tight setting on purpose and are excluded by not being
   named: a price and its unit, a plan's name and its price, and a table that
   ends a card, whose footer brings its own rule and padding. */
:is(.card, .plan, .authcol, .deploy, article, form) >
  :is(.cols-2, .cols-3, .cols-4, .metrics, .table-wrap, .deploy, .evidence, .notice,
      dl, ul, ol, pre, .plan__period, .btn-group, button) +
  :is(p, .row, .btn-group, .notice, .card, .cols-2, .cols-3, .cols-4, dl, ul, ol) {
  margin-block-start: var(--sp-05);
}
/* A product tile leads with an icon and a badge on one row; the title under it
   had nothing between the two. */
.prod > .row + .card__title { margin-block-start: var(--sp-05); }

/* A heading takes its space from the type scale when prose follows it, and the
   type scale's step is smaller than a block's. A heading directly above a
   table, a grid or a band needs the block step instead: the home page's vendor
   table sat 12px under its own heading. */
:is(.card, .plan, article, form) > :is(h2, h3, h4) +
  :is(.table-wrap, .cols-2, .cols-3, .cols-4, .metrics, .evidence, .notice, .deploy) {
  margin-block-start: var(--sp-05);
}

/* ...AND NEVER INSIDE A LAYOUT COMPONENT, which the rule above did not say and
   therefore did. A grid item with a top margin is pushed down inside its own
   row and loses the stretch that makes a row of cards end level: on the home
   page the first two product tiles measured 352px and 312px tall, forty apart
   at the top and level at the bottom, because the second tile is a `.card`
   after a `.card` and took a stacking margin written for a vertical stack. The
   second row looked correct only because BOTH its tiles matched, so they were
   wrong by the same amount. Every tile grid on the site had it.

   The space between two cards in a grid is the grid's own gap, and a layout
   component owns the space between the things it lays out. Anything with a gap
   gets the margin zeroed, whatever rule above tried to add one. */
:is(.cols-2, .cols-3, .cols-4, .grid, .metrics, .stack, .row, .btn-group) >
  :is(.card, .notice, form, article, .plan, .prod, .metric) {
  margin-block-start: 0;
}

/* --- a marked list of points --------------------------------------------------
   The same hairline mark as a plan's feature list, outside a plan. It WAS
   .plan__list, used on the access and home pages where there is no plan -- an
   element borrowed from a block it does not belong to, which is how a component
   stops meaning anything. The plan keeps .plan__list; this is everything else.
   A hairline rather than a tick glyph, because a pictographic bullet is a
   character a screen reader reads out and this is already a list. */
.ticklist { margin: var(--sp-06) 0; padding: 0; list-style: none;
            font-size: var(--ts-02); color: var(--text-secondary); }
.ticklist li { position: relative; margin-block-end: var(--sp-04);
               padding-inline-start: var(--sp-06); }
.ticklist li::before {
  content: ""; position: absolute; inset-inline-start: 0; inset-block-start: 0.55em;
  inline-size: var(--sp-03); block-size: var(--border-w); background: var(--text-disabled);
}

/* The step block, named. Its label was .step__n with no .step anywhere -- an
   element of a block that did not exist. */
.step > :last-child { margin-block-end: 0; }

/* --- BELONGS UPSTREAM, fixed here for now -------------------------------------
   `.card > :last-child { margin-top: auto }` pins the last child so an ACTION
   sits on its neighbours' baseline in a row of cards. The design system already
   knows this is wrong when the last child is prose and excludes .card__body by
   name. A LIST is the same case and is not excluded: on the docs page, whose
   cards end in a list of topics, the list was pushed 168px down its card at
   768px, detached from the heading it belongs to.

   The exclusion wants to be on the system's side and by shape rather than by
   name -- content is pinned by accident, actions on purpose. Recorded in
   the design-system findings note. */
.card > ul:last-child,
.card > ol:last-child,
.card > dl:last-child { margin-block-start: 0; }

/* --- a row whose items are not peers ------------------------------------------
   `.cols-*` stretches its children to equal height, which is right for a row of
   cards: they end level and the eye reads them as one set. It is wrong when the
   two things in the row are not the same KIND of thing -- supporting prose
   beside a data card is not a pair of peers, and stretching the short one left
   390px of empty card on the home page.

   `--start` lets each item be its own height. Use it when one side is page
   content and the other is an object; leave it off for a row of cards. */
.cols--start { align-items: start; }

/* --- the deployment diagram ---------------------------------------------------
   A drawing of where Shield sits, with three steps a reader can walk through.
   It replaced ASCII art in a <pre>, which is a diagram only to someone who
   already knows what it says.

   IT WORKS WITH NO SCRIPT. Every leg is drawn at full strength by default, so
   without JavaScript this is simply a complete diagram and the three steps
   below it are three paragraphs. The script only dims the legs that are not
   the current step, which is presentation and nothing else -- the rule this
   site is held to. */
.deploy { display: grid; gap: var(--sp-07); }
@media (min-width: 1056px) {
  /* The drawing has a width it wants (620) rather than a share of the row, so
     the track is that width and the steps take what is left. */
  .deploy { grid-template-columns: minmax(0, 620px) minmax(0, 1fr); align-items: start; }
}
.deploy__svg { min-inline-size: 0; }
@media (min-width: 1056px) { .deploy__svg { align-self: center; } }

/* LOCAL: one drawing cannot serve 1440px and 412px. A diagram scales with its
   column, so a landscape viewBox on a phone shrinks 12px labels to 5px. Two
   drawings, one shown at a time -- the hidden one leaves the accessibility tree
   with it, so a screen reader is read one diagram, not two. */
/* A DRAWING SCALED UP IS A DRAWING WITH ITS LABELS SHRUNK, and the system's
   own .diagram comment says why: the type is in user units so it scales with
   the boxes. A 960-unit viewBox stretched across a 713px column therefore
   renders its 14-unit titles at 10px and its 12-unit labels at 9. Both wide
   drawings are laid out at 620 units and capped there, so one user unit is one
   pixel at full width and the labels are the size they were drawn. Narrower
   than that they scale down together, which is the whole point of the unit. */
.diagram--wide { max-inline-size: 620px; margin-inline: auto; }
.diagram--tall { max-inline-size: 360px; margin-inline: auto; }
@media (max-width: 719px)  { .diagram--wide { display: none; } }
@media (min-width: 720px)  { .diagram--tall { display: none; } }

/* LOCAL: the system paints .diagram__arrow one colour, so a tinted edge ends in
   a grey head. Marker contents cannot inherit from the line, so the tint has to
   be its own marker. Recorded in the design-system findings note. */
.diagram__arrow--accent { fill: var(--accent); }
.diagram__arrow--good   { fill: var(--support-success); }

/* Only once the script has taken over does a leg dim. */
[data-deploy][data-js] .deploy__leg {
  opacity: 0.28;
  transition: opacity var(--dur) var(--ease);
}
[data-deploy][data-js][data-step="1"] .deploy__leg[data-leg="1"],
[data-deploy][data-js][data-step="2"] .deploy__leg[data-leg="2"],
[data-deploy][data-js][data-step="3"] .deploy__leg[data-leg="3"] { opacity: 1; }

.deploy__steps { display: grid; gap: var(--sp-04); margin: 0; padding: 0; list-style: none; counter-reset: none; }
.deploy__step {
  display: grid; grid-template-columns: var(--sp-08) minmax(0, 1fr);
  gap: var(--sp-02) var(--sp-05);
  inline-size: 100%; padding: var(--sp-05);
  background: transparent; text-align: start; cursor: pointer;
  border: var(--border-w) solid var(--border-subtle);
  font: inherit; color: inherit;
  transition: border-color var(--dur-fast) var(--ease), background var(--dur-fast) var(--ease);
}
.deploy__step:hover { border-color: var(--border-strong); background: var(--layer-02); }
.deploy__step:focus-visible {
  outline: var(--focus-w) solid var(--border-focus); outline-offset: var(--focus-offset);
}
/* aria-pressed IS the state, so the style keys on it -- there is no second
   class saying the same thing, and a screen reader is told what the eye sees. */
.deploy__step[aria-pressed="true"] { border-color: var(--accent); background: var(--layer-02); }
.deploy__n {
  grid-row: span 2;
  display: flex; align-items: center; justify-content: center;
  inline-size: var(--sp-08); block-size: var(--sp-08);
  background: var(--layer-03); color: var(--text-helper);
  font-family: var(--font-mono); font-size: var(--ts-02);
}
.deploy__step[aria-pressed="true"] .deploy__n { background: var(--accent); color: var(--text-on-accent); }
.deploy__label { font-weight: 600; color: var(--text-primary); }
.deploy__text { font-size: var(--ts-02); color: var(--text-secondary); }

/* The facade's poster and player. The design system ships both rules in its media
   layer (senua-media.css) from a version later than the one vendored here; these
   two are that layer's rules as written, and go when senua.css is re-vendored. */
.video__poster {
  position: absolute; inset: 0;
  inline-size: 100%; block-size: 100%; max-inline-size: 100%;
  object-fit: cover;
}
.video__embed {
  position: absolute; inset: 0;
  inline-size: 100%; block-size: 100%;
  border: 0;
}

/* No upper case on the marketing site (owner rule: capitals read as shouting). The design system sets these labels
   in uppercase with wide tracking; here they keep the sentence case they are written in. */
.eyebrow,
.badge,
.video__facade-meta,
.notice__kind,
.media-card__eyebrow {
  text-transform: none;
  letter-spacing: normal;
}
