@property --card-tilt-x {
  syntax: "<angle>";
  inherits: false;
  initial-value: 0deg;
}

@property --card-tilt-y {
  syntax: "<angle>";
  inherits: false;
  initial-value: 0deg;
}

@property --sheen-x {
  syntax: "<percentage>";
  inherits: false;
  initial-value: 50%;
}

@property --sheen-y {
  syntax: "<percentage>";
  inherits: false;
  initial-value: 50%;
}

:root {
  color-scheme: dark;
  --ink: #0a0b10;
  --fg: #f4f5f7;
  --muted: rgba(244, 245, 247, .65);
  --faint: rgba(244, 245, 247, .43);
  --line: rgba(255, 255, 255, .1);
  --line-strong: rgba(255, 255, 255, .2);
  --violet: #b79cff;
  --blue: #8ad9ff;
  --pink: #ff9ecf;
  --amber: #ffd9a0;
  --mint: #7ee8b2;
  --coral: #ff8a80;
  --display: "Space Grotesk", "Avenir Next", "Helvetica Neue", ui-sans-serif, system-ui, sans-serif;
  --data: "JetBrains Mono", "SFMono-Regular", Consolas, "Liberation Mono", ui-monospace, monospace;
  --prism: linear-gradient(110deg, var(--blue), var(--violet) 38%, var(--pink) 72%, var(--amber));
}

* {
  box-sizing: border-box;
}

html {
  min-width: 300px;
  min-height: 100%;
  background: var(--ink);
}

body {
  min-height: 100svh;
  margin: 0;
  overflow-x: hidden;
  color: var(--fg);
  background: var(--ink);
  font: 15px/1.55 ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

body.modal-open {
  overflow: hidden;
}

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

button,
select,
input[type="radio"] {
  cursor: pointer;
  touch-action: manipulation;
}

button:disabled,
input:disabled,
select:disabled {
  cursor: default;
  opacity: .42;
}

a:focus-visible,
button:focus-visible,
input:focus-visible,
select:focus-visible,
[tabindex="-1"]:focus-visible {
  outline: 2px solid var(--amber);
  outline-offset: 4px;
}

h1,
h2,
h3,
p {
  text-wrap: pretty;
}

noscript {
  display: block;
  width: min(1100px, calc(100% - 40px));
  margin: 40px auto;
  color: var(--coral);
}

#root,
.screen {
  min-height: 100svh;
}

.screen {
  position: relative;
  isolation: isolate;
}

.page-width {
  width: min(1104px, calc(100% - 48px));
  margin-inline: auto;
}

.sr-only {
  position: absolute !important;
  width: 1px !important;
  height: 1px !important;
  padding: 0 !important;
  margin: -1px !important;
  overflow: hidden !important;
  clip: rect(0, 0, 0, 0) !important;
  white-space: nowrap !important;
  border: 0 !important;
}

/* Above the modal layer (300): a screen change started from inside a dialog has
   to cover the dialog too, or the dialog is still lit while the page behind it
   swaps. */
.phase-veil {
  position: fixed;
  z-index: 400;
  inset: 0;
  pointer-events: none;
  background: #05060a;
  opacity: 0;
  transition: opacity 360ms ease;
}

.phase-veil.is-visible {
  pointer-events: auto;
  opacity: 1;
  transition-duration: 190ms;
}

.site-header {
  position: relative;
  z-index: 10;
  display: flex;
  min-height: 72px;
  align-items: center;
  justify-content: space-between;
  gap: 24px;
  padding-top: 20px;
}

.brand {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  color: var(--fg);
  white-space: nowrap;
}

/* Where the mark leads back to the start it is a real button, and buttons carry
   a UA border, padding and font of their own. */
.brand--home {
  padding: 0;
  background: none;
  border: 0;
  cursor: pointer;
  font: inherit;
  transition: opacity 150ms ease;
}

.brand--home:hover {
  opacity: .78;
}

/* The mark ships as artwork with its own fill, so it is placed rather than
   tinted; height drives the size because the glyph is not square. */
.brand__mark {
  height: 21px;
  width: auto;
}

.brand__name {
  font: 700 21px/1 var(--display);
  letter-spacing: .16em;
  padding-top: 2px;
}

.eyebrow {
  margin: 0;
  color: var(--violet);
  font: 700 11px/1.3 var(--data);
  letter-spacing: .28em;
  text-transform: uppercase;
  white-space: nowrap;
}

.eyebrow--mint {
  color: var(--mint);
}

.eyebrow--muted {
  color: var(--faint);
}

.prism-text {
  color: transparent;
  background: var(--prism);
  background-clip: text;
  -webkit-background-clip: text;
}

.button {
  display: inline-flex;
  min-height: 40px;
  align-items: center;
  justify-content: center;
  gap: 8px;
  padding: 8px 16px;
  color: rgba(244, 245, 247, .85);
  background: transparent;
  border: 1px solid rgba(255, 255, 255, .16);
  border-radius: 999px;
  font: 600 12px/1 var(--data);
  text-decoration: none;
  transition: color 150ms ease, border-color 150ms ease, transform 150ms ease;
}

.button:not(:disabled):hover {
  color: #fff;
  border-color: rgba(255, 255, 255, .45);
  transform: translateY(-2px);
}

.button--large {
  min-height: 54px;
  gap: 10px;
  padding: 14px 28px;
  font: 700 16px/1 var(--display);
}

.button--bright {
  color: var(--ink);
  background: var(--fg);
  border-color: var(--fg);
  box-shadow: 0 0 44px rgba(183, 156, 255, .35);
}

.button--bright:not(:disabled):hover {
  color: var(--ink);
  background: #fff;
  border-color: #fff;
  transform: translateY(-2px);
}

.header-settings {
  display: grid;
  width: 40px;
  height: 40px;
  padding: 0;
  place-items: center;
  color: rgba(244, 245, 247, .5);
  background: transparent;
  border: 0;
  transition: color 150ms ease;
}

.header-settings:hover {
  color: var(--fg);
}

/* `flex: none` because these sit in flex rows (the modal header) whose other
   child is long prose — without it the circle is squeezed into an ellipse. */
.icon-button {
  display: inline-grid;
  width: 40px;
  height: 40px;
  flex: none;
  padding: 0;
  place-items: center;
  color: var(--muted);
  background: transparent;
  border: 1px solid var(--line);
  border-radius: 50%;
}

.icon-button:hover {
  color: var(--fg);
  border-color: var(--line-strong);
}

.rise-in {
  animation: rise-in .8s cubic-bezier(.2, .8, .2, 1) both;
}

/* Landing */

.landing-screen {
  display: flex;
  flex-direction: column;
  overflow: hidden;
  background:
    radial-gradient(900px 500px at 70% -10%, rgba(183, 156, 255, .14), transparent 60%),
    radial-gradient(700px 500px at 10% 110%, rgba(138, 217, 255, .08), transparent 60%),
    var(--ink);
}

.ambient-canvas {
  position: absolute;
  z-index: 0;
  inset: 0;
  width: 100%;
  height: 100%;
  pointer-events: none;
  mask-image: radial-gradient(ellipse at center, #000 20%, transparent 88%);
  -webkit-mask-image: radial-gradient(ellipse at center, #000 20%, transparent 88%);
}

.ambient-canvas--result {
  opacity: .8;
}

.landing-main {
  position: relative;
  z-index: 2;
  display: grid;
  flex: 1;
  grid-template-columns: minmax(0, 7fr) minmax(300px, 5fr);
  gap: 32px;
  align-items: center;
  padding-block: 32px;
}

.hero-copy h1 {
  margin: 20px 0 0;
  color: #fff;
  font: 700 clamp(42px, 6vw, 80px)/.98 var(--display);
  letter-spacing: -.035em;
}

.hero-copy__lede {
  max-width: 465px;
  margin: 24px 0 0;
  color: var(--muted);
  font-size: 18px;
  line-height: 1.6;
}

.hero-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 16px;
  margin-top: 34px;
}

.availability {
  max-width: 475px;
  margin: 20px 0 0;
  color: var(--amber);
  font-size: 13px;
}

.card-studio-column {
  display: flex;
  justify-content: center;
  animation-delay: .15s;
}

.card-studio {
  display: flex;
  min-width: 0;
  flex-direction: column;
  align-items: center;
  gap: 0;
}

.card-float {
  animation: card-float 7s ease-in-out infinite;
}

/* The card drifts on its own while nobody is pointing at it, but a target that
   keeps moving is a target that is hard to hit: once the pointer is on the
   card, the ambient motion settles so its controls hold still. */
.card-float:has(.holo-card:hover),
.card-float:has(.holo-card:focus-within) {
  animation-play-state: paused;
}

.handle-field {
  display: flex;
  width: 210px;
  min-height: 34px;
  align-items: center;
  gap: 7px;
  margin-top: 12px;
  padding: 5px 12px;
  color: var(--violet);
  background: rgba(255, 255, 255, .05);
  border: 1px solid rgba(255, 255, 255, .14);
  border-radius: 999px;
  transition:
    background-color 200ms ease,
    border-color 200ms ease,
    box-shadow 200ms ease;
}

.handle-field:focus-within {
  border-color: rgba(183, 156, 255, .7);
  box-shadow: 0 0 0 3px rgba(183, 156, 255, .15);
}

.card-studio:has(.holo-card:hover)
  .handle-field:not(.is-filled):not(:focus-within) {
  animation: handle-guide 1.35s ease-in-out infinite;
}

.handle-field input {
  min-width: 0;
  flex: 1;
  padding: 0;
  color: var(--fg);
  background: transparent;
  border: 0;
  outline: 0;
  font: 500 11px/1.4 var(--data);
}

.handle-field input::placeholder {
  color: var(--faint);
}

.handle-field__valid {
  color: var(--mint);
}

.card-style-picker {
  display: flex;
  max-width: 264px;
  align-items: center;
  justify-content: center;
  gap: 8px;
  margin-top: 9px;
}

.card-style-picker fieldset {
  display: flex;
  align-items: center;
  gap: 6px;
  min-width: 0;
  margin: 0;
  padding: 0;
  border: 0;
}

.card-style-picker__options {
  display: flex;
  align-items: center;
  gap: 6px;
}

.card-style-picker__divider {
  width: 1px;
  height: 14px;
  background: rgba(255, 255, 255, .15);
}

.finish-swatch,
.shape-swatch-button {
  position: relative;
  display: grid;
  width: 22px;
  height: 22px;
  flex: 0 0 22px;
  padding: 0;
  place-items: center;
  background: rgba(255, 255, 255, .05);
  border: 1px solid rgba(255, 255, 255, .25);
  border-radius: 6px;
  cursor: pointer;
}

/* Selection reads as a second border set off from the swatch's own, drawn with
   rings rather than a thicker border: growing the border would reflow the chip
   inside it, and an outline at an offset squares off a rounded swatch. The
   inner ring is the page behind it, so the two edges stay visually separate. */
.finish-swatch.is-selected,
.shape-swatch-button.is-selected {
  border-color: rgba(255, 255, 255, .5);
  box-shadow: 0 0 0 2px var(--ink), 0 0 0 3px var(--violet);
}

/* Keyboard focus only — clicking a swatch used to leave a hard amber square
   sitting over the picker. */
.finish-swatch:has(:focus-visible),
.shape-swatch-button:has(:focus-visible) {
  border-color: var(--fg);
  box-shadow: 0 0 0 2px var(--ink), 0 0 0 3px var(--amber);
}

.finish-swatch__chip {
  display: block;
  width: 100%;
  height: 100%;
}

.shape-swatch-button svg {
  overflow: visible;
}

.shape-swatch-button path {
  fill: rgba(244, 245, 247, .5);
}

.shape-swatch-button.is-selected path {
  fill: var(--violet);
}

/* The rail is the last thing in a full-height flex column, so its bottom
   padding is dead space that `.landing-main` (flex: 1) would otherwise take:
   trimming it lets the hero sit lower and the cards finish nearer the fold. */
.card-marquee {
  position: relative;
  z-index: 3;
  padding: 8px 0 28px;
}

.card-marquee__angle {
  transform: rotate(-2deg) scale(1.06);
}

/* The rail bleeds the full viewport while everything above it is inside the
   1104px column, and a hard-edged rail makes that difference read as two
   mismatched containers. Fading it out across the column's own gutter — plus a
   little — lets it reach full strength about where the content starts, so it
   reads as one wide thing dissolving rather than a wider box. The half-opacity
   stop mid-ramp keeps the falloff gradual instead of a visible linear wipe. */
.card-marquee__window {
  overflow: hidden;
  padding-block: 32px;
  mask-image: linear-gradient(
    90deg,
    transparent 0,
    rgba(0, 0, 0, .42) max(48px, calc((100% - 1104px) / 2 * .55)),
    #000 max(150px, calc((100% - 1104px) / 2 + 74px)),
    #000 calc(100% - max(150px, calc((100% - 1104px) / 2 + 74px))),
    rgba(0, 0, 0, .42) calc(100% - max(48px, calc((100% - 1104px) / 2 * .55))),
    transparent 100%
  );
  -webkit-mask-image: linear-gradient(
    90deg,
    transparent 0,
    rgba(0, 0, 0, .42) max(48px, calc((100% - 1104px) / 2 * .55)),
    #000 max(150px, calc((100% - 1104px) / 2 + 74px)),
    #000 calc(100% - max(150px, calc((100% - 1104px) / 2 + 74px))),
    rgba(0, 0, 0, .42) calc(100% - max(48px, calc((100% - 1104px) / 2 * .55))),
    transparent 100%
  );
}

.card-marquee__track {
  display: flex;
  width: max-content;
  animation: card-marquee 44s linear infinite;
  will-change: transform;
}

.card-marquee__track:hover {
  animation-play-state: paused;
}

.card-marquee__set {
  display: flex;
  width: max-content;
  flex: 0 0 auto;
  gap: 28px;
  padding-right: 28px;
}

.card-marquee__set > div {
  flex: 0 0 auto;
}

/* GPU card */

.gpu-card {
  position: relative;
  filter: drop-shadow(0 26px 44px rgba(0, 0, 0, .6));
}

.gpu-card--hero {
  width: min(260px, 72vw);
}

.gpu-card--result {
  width: min(340px, 78vw);
}

.gpu-card--fallback {
  width: min(310px, 72vw);
}

.gpu-card--marquee {
  width: 126px;
  flex: 0 0 126px;
  filter: drop-shadow(0 12px 22px rgba(0, 0, 0, .5));
}

.gpu-card svg {
  display: block;
  width: 100%;
  height: auto;
  overflow: visible;
}

.gpu-card__portrait,
.gpu-card__foot-mark {
  pointer-events: none;
}

.gpu-card__rail {
  stroke-width: 1.5;
}

.gpu-card__score {
  font: 700 50px/1 var(--display);
  letter-spacing: -.03em;
}

.gpu-card__position {
  font: 700 19px/1 var(--data);
  letter-spacing: .12em;
}

.gpu-card__badge {
  font: 700 12px/1 var(--data);
  letter-spacing: .12em;
}

.gpu-card__api {
  font: 700 8px/1 var(--data);
  letter-spacing: .05em;
}

/* Family and weight ONLY. The device tag is the one card label whose pill is sized
   from its text: GpuCard computes the rounded-rect width as
   trackedTextWidth(tag, CARD_LAYOUT.deviceTag.size, .tracking) + 2 * padding, and
   cardCanvas draws the same tag at that same size. A `font` shorthand here also sets
   font-size, and CSS beats an SVG presentation attribute — so declaring 7px made the
   DOM card draw 7px glyphs inside a pill measured for 11px, about twice as wide as
   the text. Size and tracking belong to CARD_LAYOUT, which the geometry and the
   canvas both read; leave them off so the presentation attributes apply. */
.gpu-card__device {
  font-family: var(--data);
  font-weight: 700;
}

.gpu-card__name {
  font-family: var(--display);
  font-weight: 700;
  letter-spacing: .04em;
}

.gpu-card__stats line {
  stroke-width: 1.2;
}

.gpu-card__stat-value {
  font: 700 25px/1 var(--display);
}

.gpu-card__stat-label {
  font: 700 13px/1 var(--data);
  letter-spacing: .1em;
}

.holo-card {
  position: relative;
  width: max-content;
  perspective: 1000px;
}

.holo-card--hero {
  width: min(260px, 72vw);
}

.holo-card--result {
  width: min(340px, 78vw);
}

.holo-card__inner {
  --card-tilt-x: 0deg;
  --card-tilt-y: 0deg;

  position: relative;
  width: 100%;
  transform: rotateX(var(--card-tilt-x)) rotateY(var(--card-tilt-y));
  transform-style: preserve-3d;
}

.holo-card__sheen {
  position: absolute;
  z-index: 3;
  inset: 0;
  display: block;
  width: 100%;
  height: 100%;
  overflow: hidden;
  pointer-events: none;
  mix-blend-mode: screen;
  opacity: 0;
  transition: opacity 200ms ease;
}

.holo-card__light {
  --sheen-x: 50%;
  --sheen-y: 50%;

  width: 100%;
  height: 100%;
  background:
    radial-gradient(circle at var(--sheen-x) var(--sheen-y), rgba(255, 255, 255, .34), transparent 55%),
    conic-gradient(from 200deg at var(--sheen-x) var(--sheen-y), rgba(138, 217, 255, .14), rgba(183, 156, 255, .14), rgba(255, 158, 207, .14), rgba(255, 217, 160, .14), rgba(138, 217, 255, .14));
}

.holo-card:hover .holo-card__sheen {
  opacity: 1;
}

/* Modal */

/* Fixed to the viewport corner and below the modal layer: it is advice, so it
   must never sit over a dialog the reader opened, and it must never take space
   the page had laid out. Centered on narrow viewports, where a corner card
   would crowd the content column. */
.toast {
  position: fixed;
  z-index: 200;
  right: 24px;
  bottom: 24px;
  display: flex;
  align-items: flex-start;
  max-width: min(360px, calc(100vw - 32px));
  gap: 10px;
  padding: 12px 12px 12px 16px;
  color: var(--muted);
  font-size: 13px;
  line-height: 1.45;
  background: rgba(18, 19, 26, .95);
  border: 1px solid rgba(255, 255, 255, .12);
  border-radius: 14px;
  box-shadow: 0 18px 44px rgba(0, 0, 0, .5);
  backdrop-filter: blur(10px);
  animation: toast-in 420ms cubic-bezier(.2, .8, .2, 1) both;
}

.toast__body {
  padding-top: 5px;
  text-wrap: pretty;
}

.toast__close {
  width: 28px;
  height: 28px;
}

@keyframes toast-in {
  from {
    opacity: 0;
    transform: translateY(12px);
  }

  to {
    opacity: 1;
    transform: none;
  }
}

@media (max-width: 720px) {
  .toast {
    right: 16px;
    bottom: 16px;
    left: 16px;
    max-width: none;
  }
}

.modal-backdrop {
  position: fixed;
  z-index: 300;
  inset: 0;
  display: grid;
  overflow-y: auto;
  place-items: center;
  padding: 24px;
  background: rgba(4, 5, 8, .78);
  backdrop-filter: blur(12px);
  animation: fade-in 180ms ease both;
}

.modal {
  width: min(620px, 100%);
  max-height: min(760px, calc(100svh - 48px));
  overflow-y: auto;
  background: #12131a;
  border: 1px solid rgba(255, 255, 255, .12);
  border-radius: 20px;
  box-shadow: 0 30px 100px rgba(0, 0, 0, .65);
}

/* Its body scrolls internally, so the dialog itself stays put at full height. */
.modal--wide {
  display: flex;
  width: min(880px, 100%);
  flex-direction: column;
  overflow: hidden;
}

.modal--wide .modal__body {
  min-height: 0;
  overflow-y: auto;
}

.modal__header {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 24px;
  padding: 24px 24px 19px;
  border-bottom: 1px solid var(--line);
}

.modal__header h2 {
  margin: 0;
  font: 700 22px/1.1 var(--display);
}

.modal__header p {
  margin: 8px 0 0;
  color: var(--muted);
}

/* Keyed on which content the dialog is showing, so swapping from settings to
   the disclosure animates the content while the backdrop stays put. Tearing
   one dialog down to build another blinked the blur off and on again.

   Opacity only: sliding the body in from a few pixels below reads as the first
   row's gap starting too large and then closing, which looks like a layout bug
   rather than a transition. */
.modal__body {
  padding: 22px 24px 26px;
  animation: modal-content-in 170ms ease both;
}

.modal__footer {
  display: flex;
  gap: 10px;
  justify-content: flex-end;
  padding: 17px 24px;
  border-top: 1px solid var(--line);
}

.how-copy {
  margin: 0;
  color: var(--muted);
  font-size: 13px;
  line-height: 1.65;
}

/* Inline in running prose, as a link or as a button that opens another dialog:
   both are the same affordance to a reader, so they get the same box. */
.text-link {
  padding: 0;
  color: var(--violet);
  font: inherit;
  background: none;
  border: 0;
  text-decoration: underline;
  text-underline-offset: 2px;
}

.text-link:hover {
  color: var(--fg);
}

.trial-disciplines {
  display: grid;
  gap: 8px;
  margin-block: 18px;
}

.trial-disciplines > div {
  display: grid;
  grid-template-columns: 36px 92px 1fr;
  gap: 8px;
  align-items: baseline;
}

.trial-disciplines strong {
  color: var(--violet);
  font: 700 11px/1.4 var(--data);
}

.trial-disciplines span {
  color: var(--fg);
  font-size: 13px;
}

.trial-disciplines p {
  margin: 0;
  color: var(--faint);
  font: 500 10px/1.4 var(--data);
}

.settings-group {
  padding-bottom: 20px;
  border-bottom: 1px solid var(--line);
}

.settings-group + .settings-group {
  padding-top: 20px;
}

.settings-field {
  display: grid;
  grid-template-columns: 1fr auto;
  gap: 20px;
  align-items: center;
}

.settings-field > span:first-child {
  display: inline-flex;
  align-items: center;
  gap: 9px;
  font: 700 12px/1.3 var(--data);
}

.settings-readout {
  overflow-wrap: anywhere;
  color: var(--muted);
  font: 500 12px/1.3 var(--data);
  text-align: right;
}

.settings-hint {
  margin: 10px 0 0;
  color: var(--faint);
  font-size: 12px;
  line-height: 1.6;
}

.settings-hint--standalone {
  margin-top: 20px;
}

/* The native control drew its own bevel and focus ring inside ours, which read
   as a second outline around the box on macOS. Suppressing the platform
   appearance leaves one border, one focus ring, and a chevron we can place. */
.settings-select {
  position: relative;
  display: inline-flex;
}

/* Fills its wrapper, so the chevron the wrapper draws stays on the control's
   own edge when the row stacks on a narrow screen. */
.settings-select select {
  flex: 1;
}

.settings-select::after {
  position: absolute;
  top: 50%;
  right: 15px;
  width: 7px;
  height: 7px;
  border-right: 2px solid var(--muted);
  border-bottom: 2px solid var(--muted);
  content: "";
  pointer-events: none;
  transform: translateY(-70%) rotate(45deg);
}

.settings-field select {
  min-height: 42px;
  padding: 8px 38px 8px 13px;
  appearance: none;
  color: var(--fg);
  font-size: 13px;
  background: #171923;
  border: 1px solid var(--line-strong);
  border-radius: 10px;
  cursor: pointer;
}

.settings-field select:hover {
  border-color: var(--fg);
}

/* A dropdown's own list is painted by the platform, which does not inherit the
   page's dark ground on every engine. */
.settings-field option {
  color: var(--fg);
  background: #171923;
}

/* The full list is a dozen lines of inventory that only some readers want, and
   printing it made the dialog taller than the screen it opens over. It stays a
   click away, in the place that names it. */
.data-disclosure {
  margin-top: 16px;
  padding-top: 14px;
  border-top: 1px solid var(--line);
}

.data-disclosure > summary {
  display: flex;
  align-items: center;
  gap: 9px;
  color: var(--violet);
  font: 700 12px/1.4 var(--data);
  cursor: pointer;
  list-style: none;
}

.data-disclosure > summary::-webkit-details-marker {
  display: none;
}

.data-disclosure > summary::before {
  width: 6px;
  height: 6px;
  border-right: 2px solid currentcolor;
  border-bottom: 2px solid currentcolor;
  content: "";
  transform: rotate(-45deg);
  transition: transform 140ms ease;
}

.data-disclosure[open] > summary::before {
  transform: translateY(-2px) rotate(45deg);
}

.data-disclosure > summary:hover {
  color: var(--fg);
}

.data-disclosure ul {
  display: grid;
  gap: 8px;
  margin: 14px 0 0;
  padding-left: 20px;
  color: var(--muted);
  font-size: 13px;
}

.data-disclosure p {
  margin: 14px 0 0;
  color: var(--faint);
  font-size: 12px;
  line-height: 1.6;
}

/* Running — intentionally animation-free while WebGPU owns the device, apart
   from the small compositor-only census spinner and activity-gauge needle. */

.running-screen {
  display: flex;
  flex-direction: column;
  background: #07080c;
}

.running-screen *,
.running-screen *::before,
.running-screen *::after {
  animation: none !important;
  transition: none !important;
  box-shadow: none !important;
  filter: none !important;
  backdrop-filter: none !important;
}

.running-main {
  display: flex;
  width: min(624px, calc(100% - 48px));
  flex: 1;
  flex-direction: column;
  justify-content: center;
  margin-inline: auto;
  padding-block: 36px 56px;
}

.running-heading {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  justify-content: space-between;
  gap: 16px;
}

.running-heading h1 {
  display: block;
  width: max-content;
  margin: 4px 0 0;
  padding: .02em .035em .04em 0;
  overflow: visible;
  font: 700 clamp(64px, 11vw, 104px)/1 var(--display);
  letter-spacing: -.03em;
}

/* The estimate under the clock rewords itself as the run proceeds ("about 30 sec
   left" → "finishing this operation"); one line, always, so the screen below it
   cannot move. */
.running-heading__unit {
  display: block;
  margin-top: 3px;
  overflow: hidden;
  color: var(--faint);
  font: 500 10px/1 var(--data);
  font-variant-numeric: tabular-nums;
  letter-spacing: .12em;
  text-overflow: ellipsis;
  text-transform: uppercase;
  white-space: nowrap;
}

.gpu-gauge {
  position: relative;
  width: 132px;
  height: 102px;
  margin-left: auto;
}

.gpu-gauge svg {
  display: block;
  width: 100%;
  height: 82px;
  overflow: visible;
}

.gpu-gauge__track,
.gpu-gauge__arc {
  fill: none;
  stroke-width: 7;
  stroke-linecap: round;
}

.gpu-gauge__track {
  stroke: rgba(255, 255, 255, .08);
}

.gpu-gauge__arc {
  stroke: url("#gpu-gauge-gradient");
}

.gpu-gauge__ticks {
  fill: none;
  stroke: rgba(244, 245, 247, .3);
  stroke-width: 3.5;
  stroke-linecap: round;
}

.gpu-gauge__needle {
  fill: #d6c6ff;
  transform-box: view-box;
  transform-origin: 60px 54px;
}

.gpu-gauge__needle circle {
  fill: #090a0f;
  stroke: #d6c6ff;
  stroke-width: 2;
}

/* The run suppresses decorative motion while the device is busy. This small,
   compositor-only needle is the deliberate exception: it makes the estimate
   readable as a live instrument instead of another progress control. */
.running-screen .gpu-gauge__needle {
  transition: transform 650ms cubic-bezier(.2, .75, .25, 1) !important;
}

.gpu-gauge__readout {
  position: absolute;
  right: 0;
  bottom: 0;
  left: 0;
  display: grid;
  justify-items: center;
  justify-content: center;
  gap: 2px;
  color: var(--muted);
  font-family: var(--data);
}

.gpu-gauge__readout strong {
  color: #fff;
  font-size: 20px;
  line-height: 1;
}

.gpu-gauge__readout small {
  color: var(--faint);
  font-size: 8.5px;
  line-height: 1;
  letter-spacing: .16em;
  text-transform: uppercase;
}

.mosaic-field {
  position: relative;
  margin-top: 32px;
}

.mosaic {
  display: grid;
  grid-template-columns: repeat(24, minmax(0, 1fr));
  gap: 3px;
}

/* Two independent inset marks compose on one tile — the launch-bound ring and
   the rating-anchor underline can both apply — so each owns a custom property
   instead of a `box-shadow` declaration that would overwrite the other. */
.mosaic__cell {
  --tile-ring: 0 0 0 0 transparent;
  --tile-mark: 0 0 0 0 transparent;
  aspect-ratio: 1;
  background: rgba(255, 255, 255, .05);
  border-radius: 2px;
  box-shadow: var(--tile-ring), var(--tile-mark);
}

/* One hue, stepped light-to-dark against the dark surface: the tile colour is a
   magnitude (share of the ceiling this device measured for itself), so it rides
   a single sequential ramp. The two ratio-less states sit deliberately off that
   ramp — neither is "the lowest step" — and differ from each other, because one
   operation was never timed while the other was timed and came back too small
   to compare. The hollow violet ring says a measurement exists without claiming
   a magnitude for it. */
.mosaic__cell.is-complete {
  background: rgba(183, 156, 255, .45);
}

.mosaic__cell--reach-untimed.is-complete {
  background: rgba(255, 255, 255, .1);
}

.mosaic__cell--reach-launch.is-complete {
  --tile-ring: inset 0 0 0 1px rgba(183, 156, 255, .45);
  background: rgba(183, 156, 255, .07);
}

.mosaic__cell--reach-0.is-complete {
  background: rgba(183, 156, 255, .3);
}

.mosaic__cell--reach-1.is-complete {
  background: rgba(183, 156, 255, .48);
}

.mosaic__cell--reach-2.is-complete {
  background: rgba(183, 156, 255, .66);
}

.mosaic__cell--reach-3.is-complete {
  background: rgba(183, 156, 255, .84);
}

.mosaic__cell--reach-4.is-complete {
  background: rgba(214, 198, 255, 1);
}

.mosaic__cell.is-current {
  background: var(--fg);
}

/* Half the core rotates per session and cannot move the rating, so the tiles
   that can are marked. It is a separate channel from the colour ramp: an
   anchor and a rotating operation at the same reach stay the same shade. */
.mosaic__cell.is-rated {
  --tile-mark: inset 0 -2px 0 0 rgba(255, 255, 255, .38);
}

/* Each core operation owns one tile; the outline keeps the hovered coordinate
   visible beneath its tooltip. An outline rather than a shadow, so it composes
   with whatever inset marks the tile already carries. */
.mosaic__cell.is-hovered {
  outline: 1px solid rgba(255, 255, 255, .85);
}

/* Both captions change length when the rating set completes — "119 operations
   sampled" becomes "120 rating operations complete" — and the running screen is
   vertically centred, so a caption that wrapped to a second line would move the
   whole screen. A two-track grid with single-line cells keeps the block exactly
   one row tall whatever the text says. */
.mosaic-summary {
  display: grid;
  grid-template-columns: auto auto;
  justify-content: space-between;
  gap: 5px 14px;
  margin-top: 10px;
  color: var(--muted);
  font: 500 10px/1.3 var(--data);
  letter-spacing: .04em;
}

.mosaic-summary span {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.mosaic-summary span:last-child {
  color: var(--faint);
}

.mosaic-tip {
  position: absolute;
  z-index: 6;
  display: grid;
  gap: 3px;
  max-width: 280px;
  padding: 9px 11px;
  background: rgba(10, 11, 16, .96);
  border: 1px solid rgba(255, 255, 255, .16);
  border-radius: 10px;
  box-shadow: 0 12px 30px rgba(0, 0, 0, .5);
  pointer-events: none;
  transform: translate(-50%, calc(-100% - 9px));
}

.mosaic-tip.is-below {
  transform: translate(-50%, 9px);
}

/* Wraps rather than running out of the box: the longest headline an untimed
   tile can carry is wider than the tooltip is allowed to be, and `nowrap` spilled
   it across the mosaic instead of taking a second line. */
.mosaic-tip strong {
  color: #fff;
  font: 700 13px/1.25 var(--data);
}

.mosaic-tip__op {
  overflow-wrap: anywhere;
  color: var(--muted);
  font: 500 11px/1.3 var(--data);
}

.mosaic-tip__facts {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  color: var(--faint);
  font: 500 11px/1.3 var(--data);
}

.op-ticker {
  display: grid;
  align-items: stretch;
  margin-top: 24px;
  padding: 18px;
  gap: 18px 24px;
  grid-template-columns: minmax(0, 1fr) minmax(0, 196px);
  background: rgba(255, 255, 255, .03);
  border: 1px solid var(--line);
  border-radius: 14px;
}

.op-ticker__label {
  color: var(--faint);
  font: 500 10px/1 var(--data);
  letter-spacing: .22em;
  text-transform: uppercase;
}

.op-ticker__primary {
  display: flex;
  min-width: 0;
  min-height: 88px;
  flex-direction: column;
}

.op-ticker__label-row,
.op-ticker__context > .op-ticker__label {
  display: flex;
  height: 10px;
  align-items: center;
}

.op-ticker__label-row {
  gap: 8px;
}

.op-ticker__op {
  margin: 14px 0 0;
  overflow: hidden;
  font: 400 20px/1.2 var(--data);
  text-overflow: ellipsis;
  white-space: nowrap;
}

.op-ticker__op strong {
  color: #fff;
  font-weight: 700;
}

.census-spinner {
  width: 15px;
  height: 15px;
  flex: none;
  border: 2px solid rgba(183, 156, 255, .18);
  border-top-color: var(--violet);
  border-radius: 50%;
}

/* The running screen globally suppresses motion to keep benchmark overhead
   negligible. This transform is an explicit startup-status exception. */
.running-screen .census-spinner {
  animation: census-spin 800ms linear infinite !important;
}

.op-ticker__domain {
  color: rgba(244, 245, 247, .38);
  font-size: 14px;
}

.op-ticker__meta {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 7px;
  min-height: 19px; /* one chip row, so the pre-run placeholder matches */
  margin: auto 0 0;
  padding-top: 16px;
  color: var(--faint);
  font: 500 11px/1 var(--data);
}

.op-chip {
  padding: 4px 8px;
  color: rgba(244, 245, 247, .78);
  background: rgba(255, 255, 255, .06);
  border-radius: 999px;
  letter-spacing: .08em;
  text-transform: uppercase;
}

.op-chip--bench {
  color: var(--blue);
  background: rgba(138, 217, 255, .12);
}

.op-chip--test {
  color: var(--mint);
  background: rgba(126, 232, 178, .12);
}

.op-ticker__history,
.op-ticker__measures {
  height: 76px; /* five rows are reserved before any result arrives */
  margin: 7px 0 0;
  overflow: hidden;
  padding: 0;
  list-style: none;
}

.op-ticker__history li,
.op-ticker__measures li {
  color: var(--faint);
  font: 500 10.5px/1.45 var(--data);
}

.op-ticker__history li {
  display: flex;
  justify-content: space-between;
  gap: 10px;
}

.op-ticker__history li:first-child:not(.op-ticker__empty) {
  color: var(--muted);
}

.op-ticker__history li > span:first-child {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.op-ticker__history li > span:last-child {
  flex: none;
  opacity: .72;
}

.op-ticker__empty {
  white-space: nowrap;
}

.op-ticker__outcome {
  display: inline-flex;
  gap: 7px;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

.op-outcome--pass {
  color: var(--mint);
}

.op-outcome--flagged {
  color: var(--coral);
}

.run-notice {
  margin: 9px 0 0;
  color: var(--amber);
  font-size: 12px;
}

.running-actions {
  display: flex;
  align-items: center;
  gap: 16px;
  margin-top: 28px;
}

/* Every label stacks in one cell, so the control is as wide as the longest of
   them and swapping between them never resizes it. */
.swap-label {
  display: inline-grid;
  place-items: center;
}

.swap-label > span {
  grid-area: 1 / 1;
}

.swap-label > .is-hidden {
  visibility: hidden;
}

.running-details-toggle {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 8px 0;
  color: var(--muted);
  background: none;
  border: 0;
  font: 500 12px/1 var(--data);
}

.running-details-toggle svg.is-open {
  transform: rotate(180deg);
}

.running-visible-note {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  margin-left: auto;
  color: var(--faint);
  font: 500 11px/1.3 var(--data);
}

.running-details {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 0;
  margin-top: 14px;
  padding: 12px 14px;
  color: var(--muted);
  background: rgba(255, 255, 255, .03);
  border: 1px solid var(--line);
  border-radius: 12px;
  font-family: var(--data);
}

.running-details article {
  padding-inline: 12px;
  border-right: 1px solid var(--line);
}

.running-details article:last-of-type {
  border-right: 0;
}

.running-details span {
  display: block;
  color: var(--faint);
  font-size: 8px;
  letter-spacing: .15em;
  text-transform: uppercase;
}

.running-details strong {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  margin-top: 5px;
  color: rgba(244, 245, 247, .85);
  font-size: 10px;
}

.running-details > p {
  grid-column: 1 / -1;
  margin: 11px 12px 0;
  overflow: hidden;
  color: var(--faint);
  font-size: 9px;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.run-alert {
  display: grid;
  grid-template-columns: 28px 1fr;
  gap: 14px;
  margin-top: 22px;
  padding: 17px;
  color: var(--amber);
  background: rgba(255, 217, 160, .06);
  border: 1px solid rgba(255, 217, 160, .2);
  border-radius: 14px;
}

.run-alert.is-actionable {
  color: var(--coral);
  background: rgba(255, 138, 128, .06);
  border-color: rgba(255, 138, 128, .25);
}

.run-alert h2 {
  margin: 0;
  color: var(--fg);
  font: 700 16px/1.2 var(--display);
}

.run-alert p {
  margin: 6px 0 0;
  color: var(--muted);
  font-size: 13px;
}

.run-alert__actions {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  margin-top: 14px;
}

/* Reveal */

.reveal-screen {
  position: fixed;
  z-index: 50;
  inset: 0;
  isolation: isolate;
  overflow: hidden;
  color: var(--fg);
  background:
    radial-gradient(circle at 50% 47%, rgba(64, 40, 130, .16), transparent 32%),
    #050409;
}

.reveal-screen::before {
  position: absolute;
  z-index: 3;
  inset: 0;
  content: "";
  pointer-events: none;
  background:
    radial-gradient(circle at 50% 48%, transparent 0 25%, rgba(5, 4, 9, .15) 52%, rgba(5, 4, 9, .94) 100%),
    linear-gradient(180deg, rgba(0, 0, 0, .62), transparent 25%, transparent 74%, rgba(0, 0, 0, .66));
}

.reveal-screen::after {
  position: absolute;
  z-index: 7;
  inset: 0;
  content: "";
  pointer-events: none;
  background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 180 180' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.92' numOctaves='2' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)' opacity='.32'/%3E%3C/svg%3E");
  mix-blend-mode: soft-light;
  opacity: .09;
}

.reveal-screen__haze {
  position: absolute;
  z-index: 1;
  top: 50%;
  left: 50%;
  width: min(92vw, 1100px);
  aspect-ratio: 1;
  pointer-events: none;
  background: radial-gradient(circle, rgba(122, 84, 255, .1), rgba(28, 14, 64, .04) 43%, transparent 72%);
  border-radius: 50%;
  filter: blur(24px);
  transform: translate(-50%, -50%);
  transition: opacity 1.2s ease, transform 2s cubic-bezier(.2, .8, .2, 1);
}

.reveal-phase-opening .reveal-screen__haze {
  opacity: .74;
  transform: translate(-50%, -50%) scale(1.18);
}

.reveal-phase-charging .reveal-screen__haze {
  opacity: .62;
  transform: translate(-50%, -50%) scale(1.08);
}

.reveal-stage {
  position: absolute;
  z-index: 1;
  inset: 0;
}

.reveal-canvas {
  display: block;
  width: 100%;
  height: 100%;
}

.reveal-flash {
  position: absolute;
  z-index: 6;
  inset: 0;
  pointer-events: none;
  background: radial-gradient(circle at 50% 48%, rgba(255, 250, 224, .95), rgba(255, 220, 119, .72) 7%, rgba(183, 156, 255, .34) 23%, transparent 52%);
  opacity: 0;
}

.reveal-phase-opening .reveal-flash {
  animation: reveal-impact 380ms cubic-bezier(.16, .7, .25, 1) both;
}

/* Composed onto `.eyebrow`, which supplies the type treatment. */
.reveal-eyebrow {
  position: absolute;
  z-index: 10;
  top: 11%;
  left: 50%;
  color: var(--muted);
  transform: translateX(-50%);
}

.reveal-prompt {
  position: absolute;
  z-index: 14;
  bottom: clamp(24px, 4.3vh, 48px);
  left: 50%;
  display: flex;
  min-width: 280px;
  align-items: center;
  flex-direction: column;
  pointer-events: none;
  text-align: center;
  transform: translateX(-50%);
  transition: opacity 240ms ease;
}

.reveal-phase-opening .reveal-prompt {
  opacity: 0;
}

.reveal-prompt > strong {
  color: #e4c878;
  font: 800 clamp(12px, 1.15vw, 15px)/1 var(--data);
  letter-spacing: .3em;
  text-transform: uppercase;
  text-shadow: 0 0 22px rgba(151, 110, 255, .55);
  animation: reveal-charge 520ms ease-in-out infinite alternate;
}

.reveal-prompt button {
  position: relative;
  display: inline-flex;
  align-items: center;
  gap: 9px;
  padding: 12px 18px;
  color: rgba(250, 238, 198, .9);
  background: rgba(8, 5, 18, .5);
  border: 1px solid rgba(228, 200, 120, .4);
  border-radius: 999px;
  box-shadow: 0 0 24px rgba(151, 110, 255, .1);
  backdrop-filter: blur(10px);
  font: 800 10px/1 var(--data);
  letter-spacing: .16em;
  text-transform: uppercase;
  pointer-events: auto;
  transition: color 180ms ease, border-color 180ms ease, transform 180ms ease;
}

.reveal-prompt button:hover {
  color: #fff;
  border-color: rgba(228, 200, 120, .78);
  transform: translateY(-2px);
}

/* The box tracks the button through CSS geometry properties; only the corner
   radius and the dash length are measured (see AutoAdvanceTrace). No `rx` here:
   it would override the measured one, and any value large enough to read as a
   pill is clamped per-axis into an ellipse. */
.reveal-prompt__trace {
  position: absolute;
  inset: -3px;
  width: calc(100% + 6px);
  height: calc(100% + 6px);
  overflow: visible;
  pointer-events: none;
}

/* No `rx` rule: a CSS corner radius would beat the measured presentation
   attribute, and any value big enough to read as a pill is clamped per-axis
   (rx to half the width, ry to half the height) into an ellipse. */
.reveal-prompt__trace rect {
  x: 2px;
  y: 2px;
  width: calc(100% - 4px);
  height: calc(100% - 4px);
  fill: none;
  stroke-linecap: round;
  visibility: hidden;
}

/* The dash length arrives from script; drawing before it would flash a full
   undashed ring. */
.reveal-prompt__trace[data-measured] rect {
  visibility: visible;
  animation: reveal-trace 5.2s linear forwards;
}

.reveal-prompt__line {
  stroke-width: 1.5;
  opacity: .9;
}

.reveal-prompt__glow {
  stroke-width: 3;
  filter: blur(6px);
  opacity: .55;
}

.reveal-skip {
  position: absolute;
  z-index: 14;
  bottom: clamp(24px, 4.3vh, 48px);
  left: clamp(20px, 3vw, 36px);
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 8px;
  color: rgba(244, 245, 247, .4);
  background: transparent;
  border: 0;
  font: 500 11px/1 var(--data);
}

.reveal-skip:hover {
  color: rgba(244, 245, 247, .8);
}

.reveal-sound {
  position: absolute;
  z-index: 14;
  bottom: clamp(24px, 4.3vh, 48px);
  right: clamp(20px, 3vw, 36px);
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 8px;
  color: rgba(244, 245, 247, .4);
  background: transparent;
  border: 0;
  font: 500 11px/1 var(--data);
}

.reveal-sound:hover {
  color: rgba(244, 245, 247, .8);
}

.reveal-sound[aria-pressed="true"] {
  color: rgba(183, 156, 255, .72);
}

.reveal-sound[aria-pressed="true"]:hover {
  color: rgba(183, 156, 255, 1);
}

.reveal-fallback {
  position: absolute;
  z-index: 2;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -48%);
}

/* Result */

/* The third radial sits under the card column. A dark card on a near-black page
   loses its own rim: lifting the light immediately behind it gives every finish,
   including the dark ones, a background to have an edge against. */
.result-screen {
  display: flex;
  flex-direction: column;
  overflow-x: hidden;
  overflow-y: auto;
  background:
    radial-gradient(800px 460px at 24% 20%, rgba(183, 156, 255, .12), transparent 60%),
    radial-gradient(680px 620px at 21% 56%, rgba(196, 178, 255, .1), transparent 66%),
    radial-gradient(600px 400px at 85% 90%, rgba(138, 217, 255, .07), transparent 60%),
    #0d0e15;
}

/* Holds the glows to the screen box. They are placed past its edges on purpose,
   and their containing block is a scroll container, so unclipped they add their
   overhang to the scrollable area — several hundred pixels of blank page below
   the content. Clipping keeps the look and removes the scroll. */
.page-glow-layer {
  position: absolute;
  z-index: 0;
  overflow: hidden;
  inset: 0;
  pointer-events: none;
}

.page-glow {
  position: absolute;
  z-index: 0;
  width: min(52vw, 760px);
  aspect-ratio: 1;
  pointer-events: none;
  border-radius: 50%;
  filter: blur(90px);
  opacity: .07;
}

.page-glow--violet {
  top: -25%;
  left: -18%;
  background: var(--violet);
}

.page-glow--blue {
  right: -20%;
  bottom: -35%;
  background: var(--blue);
}

.result-header {
  flex: 0 0 auto;
  padding-bottom: 2px;
}

.result-header__actions {
  display: flex;
  align-items: center;
  gap: 10px;
}

.result-main {
  position: relative;
  z-index: 2;
  display: grid;
  min-height: 0;
  flex: 1;
  grid-template-columns: minmax(300px, 5fr) minmax(0, 7fr);
  gap: 48px;
  align-items: center;
  padding-block: 16px 28px;
}

.result-card-column {
  display: flex;
  min-width: 0;
  align-items: center;
  flex-direction: column;
  gap: 14px;
}

.result-share-actions {
  display: flex;
  align-items: center;
  gap: 9px;
}

.result-share-actions .button:not(:first-child) {
  width: 40px;
  padding-inline: 0;
}

.copy-status {
  min-height: 9px;
  margin: -5px 0 0;
  color: var(--mint);
  font: 500 9px/1 var(--data);
}

.result-copy {
  min-width: 0;
  animation-delay: .1s;
}

.result-title-row {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  justify-content: space-between;
  gap: 12px 24px;
  margin-top: 8px;
}

.result-title-row h1 {
  min-width: 0;
  margin: 0;
  overflow: hidden;
  color: #fff;
  font: 700 clamp(30px, 3.4vw, 43px)/1.05 var(--display);
  letter-spacing: -.035em;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.result-badges {
  display: flex;
  gap: 8px;
  padding-bottom: 4px;
}

.result-badge {
  display: inline-flex;
  align-items: center;
  min-height: 24px;
  padding: 4px 10px;
  color: var(--fg);
  border: 1px solid rgba(255, 255, 255, .18);
  border-radius: 999px;
  font: 700 9px/1 var(--data);
  letter-spacing: .08em;
}

.result-badge--rating {
  color: var(--violet);
  background: rgba(183, 156, 255, .08);
  border-color: rgba(183, 156, 255, .34);
}

.result-overview {
  display: grid;
  grid-template-columns: minmax(250px, 1fr) minmax(210px, .9fr);
  gap: 30px;
  align-items: center;
  margin-top: 22px;
}

.rating-radar {
  display: flex;
  flex-direction: column;
  align-items: center;
}

.rating-radar svg {
  display: block;
  overflow: visible;
}

.rating-radar polygon,
.rating-radar line {
  stroke-width: 1;
}

.rating-radar polygon.rating-radar__score {
  fill: rgba(183, 156, 255, .2);
  stroke: var(--violet);
  stroke-width: 1.5;
}

.rating-radar__point {
  fill: var(--amber);
  filter: drop-shadow(0 0 4px rgba(255, 217, 160, .8));
}

.rating-radar__label {
  fill: var(--fg);
  font: 700 13px/1 var(--data);
  letter-spacing: .1em;
}

.rating-radar__value {
  fill: var(--violet);
  font: 700 15px/1 var(--display);
}

.rating-radar__center {
  fill: var(--violet);
  font: 700 27px/1 var(--display);
}

.rating-radar__center-label {
  fill: var(--faint);
  font: 700 8px/1 var(--data);
  letter-spacing: .2em;
}

/* Hover: the pointed-at axis comes forward and the rest recede, so the centre
   readout is unambiguously about one discipline. */
.rating-radar__axis {
  transition: opacity 150ms ease;
}

.rating-radar__axis.is-dimmed {
  opacity: .4;
}

.rating-radar__spoke {
  stroke: rgba(255, 255, 255, .1);
}

.rating-radar__axis.is-hovered .rating-radar__spoke {
  stroke: rgba(255, 255, 255, .4);
  stroke-width: 1.5;
}

.rating-radar__axis.is-hovered .rating-radar__label {
  fill: var(--violet);
}

.rating-radar__axis.is-hovered .rating-radar__value {
  fill: var(--fg);
}

.rating-radar__point {
  transition: r 150ms ease, fill 150ms ease;
}

.rating-radar__axis.is-hovered .rating-radar__point {
  fill: #fff;
}

.rating-radar__center.is-stat {
  fill: #fff;
}

.rating-radar__wedge {
  fill: transparent;
}

/* The spoke labels overhang the svg box, so the caption clears them rather than
   tucking under the bottom one. It is centred under the radar and its height is
   reserved for the name plus a wrapped description, because a caption that grew
   on hover would nudge everything below it. */
/* A grid rather than a flow: every caption occupies the one cell, so the block
   is as tall as the tallest description instead of as tall as the one being
   hovered, and nothing below it moves. */
.rating-radar__caption {
  display: grid;
  max-width: 280px;
  margin: 16px 0 0;
  color: var(--faint);
  font: 500 11px/1.4 var(--data);
  text-align: center;
  text-wrap: balance;
}

.rating-radar__caption > span {
  display: flex;
  grid-area: 1 / 1;
  flex-direction: column;
  gap: 4px;
  align-self: start;
}

.rating-radar__caption > .is-hidden {
  visibility: hidden;
}

.rating-radar__caption strong {
  color: var(--fg);
  font: 700 9px/1 var(--data);
  letter-spacing: .16em;
  text-transform: uppercase;
}

.census-list {
  display: grid;
  gap: 12px;
}

.census-tile {
  display: flex;
  align-items: center;
  gap: 14px;
  padding: 13px 18px;
  background: rgba(255, 255, 255, .04);
  border: 1px solid rgba(255, 255, 255, .09);
  border-radius: 12px;
  transition: border-color 160ms ease, background 160ms ease, transform 160ms ease;
}

.census-tile:hover {
  background: rgba(183, 156, 255, .06);
  border-color: rgba(183, 156, 255, .4);
  transform: translateY(-2px);
}

.census-tile__icon {
  display: grid;
  width: 38px;
  height: 38px;
  flex: 0 0 38px;
  place-items: center;
  color: var(--violet);
  background: rgba(183, 156, 255, .1);
  border: 1px solid rgba(183, 156, 255, .18);
  border-radius: 8px;
}

.census-tile div > span {
  display: block;
  color: var(--faint);
  font: 700 9px/1 var(--data);
  letter-spacing: .18em;
  text-transform: uppercase;
}

.census-tile strong {
  display: block;
  margin-top: 6px;
  color: #fff;
  font: 700 23px/1 var(--display);
  white-space: nowrap;
}

.census-tile small {
  color: var(--muted);
  font: 500 12px/1 var(--data);
}

.comparison-panel {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 20px 36px;
  margin-top: 22px;
  padding: 18px 22px;
  background: rgba(255, 255, 255, .04);
  border: 1px solid rgba(255, 255, 255, .09);
  border-radius: 12px;
}

.comparison-panel > div:first-child {
  flex: 0 0 auto;
}

.comparison-panel h2 {
  margin: 0;
  color: #fff;
  font: 700 26px/1 var(--display);
  letter-spacing: -.03em;
  white-space: nowrap;
}

.comparison-panel p {
  max-width: 210px;
  margin: 7px 0 0;
  color: var(--faint);
  font: 500 9px/1.4 var(--data);
}

.tier-rail {
  position: relative;
  min-width: 250px;
  flex: 1;
  padding-top: 26px;
}

/* The label and the line under it are one element, so the pointer cannot drift
   away from the position it names. */
.tier-rail__marker {
  position: absolute;
  top: 0;
  display: flex;
  align-items: center;
  flex-direction: column;
  gap: 4px;
  color: var(--fg);
  font: 700 8px/1 var(--data);
  letter-spacing: .12em;
  white-space: nowrap;
  transform: translateX(-50%);
}

.tier-rail__marker::after {
  content: "";
  width: 2px;
  height: 20px;
  background: linear-gradient(180deg, var(--amber), rgba(228, 200, 120, .35));
  border-radius: 1px;
}

.tier-rail__bar {
  position: relative;
  display: flex;
  height: 10px;
  background: linear-gradient(90deg, #8f6238, #c8d0d8 33%, #e4c878 66%, #fffef8);
  border-radius: 999px;
  filter: saturate(.22) brightness(.58);
  opacity: .72;
}

/* Tier boundaries, one per gap between the four equal segments. */
.tier-rail__bar i {
  width: 1px;
  margin-left: calc(25% - 1px);
  background: rgba(10, 11, 16, .55);
}

.tier-rail__labels {
  display: flex;
  margin-top: 8px;
  color: rgba(244, 245, 247, .35);
  font: 700 8px/1 var(--data);
  letter-spacing: .12em;
  text-transform: uppercase;
}

.tier-rail__labels span {
  flex: 1;
  text-align: center;
}

.tier-rail__labels .is-current {
  color: var(--amber);
}

.result-footnotes {
  display: flex;
  flex-wrap: wrap;
  gap: 7px 16px;
  margin-top: 14px;
  color: var(--faint);
  font: 500 9px/1.45 var(--data);
}

.result-footnotes p {
  margin: 0;
}

.result-footnotes p:first-child {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  color: var(--muted);
}

.result-error {
  margin: 9px 0 0;
  color: var(--coral);
  font-size: 11px;
}

/* A caveat about how the trial ran, not a failure: it sits above the footnotes
   with a rule of its own, loud enough that nobody reads a throttled score as
   their hardware's, quiet enough that it does not compete with the card. */
.result-caution {
  display: flex;
  gap: 10px;
  align-items: flex-start;
  margin: 18px 0 0;
  padding: 11px 13px;
  color: var(--muted);
  background: rgba(255, 217, 160, .06);
  border: 1px solid rgba(255, 217, 160, .26);
  border-radius: 11px;
  font-size: 12px;
  line-height: 1.45;
}

.result-caution svg {
  flex: none;
  margin-top: 1px;
  color: var(--amber);
}

.report-stats {
  display: grid;
  gap: 10px;
  grid-template-columns: repeat(auto-fit, minmax(126px, 1fr));
}

.report-stats article {
  padding: 12px 14px;
  background: rgba(255, 255, 255, .04);
  border: 1px solid rgba(255, 255, 255, .09);
  border-radius: 10px;
}

.report-stats span {
  display: block;
  color: var(--faint);
  font: 700 8px/1 var(--data);
  letter-spacing: .18em;
  text-transform: uppercase;
}

.report-stats strong {
  display: block;
  margin-top: 8px;
  color: #fff;
  font: 700 21px/1 var(--display);
}

/* The detail line can be an operation name, which is longer than the tile. */
.report-stats small {
  display: block;
  margin-top: 5px;
  overflow-wrap: anywhere;
  color: var(--muted);
  font: 500 10px/1.3 var(--data);
}

.report-note {
  margin: 14px 0 0;
  color: var(--faint);
  font: 500 10px/1.5 var(--data);
}

/* The list is the long part of this dialog, so it carries the scroll: the
   summary above it stays visible while the rows move. */
.report-table {
  margin-top: 16px;
  max-height: min(42vh, 380px);
  overflow: auto;
  border: 1px solid var(--line);
  border-radius: 10px;
}

.report-table:focus-visible {
  outline: 2px solid var(--violet);
  outline-offset: 2px;
}

.report-table table {
  width: 100%;
  min-width: 520px;
  border-collapse: collapse;
  table-layout: fixed;
}

.report-column--operation { width: 38%; }
.report-column--correctness { width: 21%; }
.report-column--best { width: 11%; }
.report-column--reach { width: 30%; }

.report-table thead th {
  position: sticky;
  top: 0;
  z-index: 1;
  padding: 9px 14px;
  color: var(--faint);
  background: #171820;
  border-bottom: 1px solid var(--line);
  font: 700 8px/1 var(--data);
  letter-spacing: .16em;
  text-align: left;
  text-transform: uppercase;
}

.report-table tbody tr {
  border-bottom: 1px solid rgba(255, 255, 255, .05);
}

.report-table tbody tr:last-child {
  border-bottom: 0;
}

.report-table tbody tr:hover {
  background: rgba(183, 156, 255, .06);
}

.report-table td,
.report-table tbody th {
  padding: 8px 14px;
  font: 500 11px/1.3 var(--data);
  text-align: left;
  vertical-align: middle;
}

.report-table tbody th strong {
  display: block;
  color: var(--fg);
  font: 700 12px/1.25 var(--data);
  overflow-wrap: anywhere;
}

.report-table tbody th span {
  color: var(--faint);
  font: 500 9px/1.3 var(--data);
  overflow-wrap: anywhere;
}

.report-time {
  color: var(--fg);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

.report-muted {
  color: var(--faint);
}

.report-pass {
  color: var(--mint);
}

.report-fail {
  color: var(--coral);
}

/* Bar plus number: the bar is for scanning down the column, the number for
   reading one row. Same five-step ramp as the progress mosaic. */
.report-reach {
  position: relative;
  display: block;
  min-width: 76px;
  padding: 4px 7px;
  color: var(--fg);
  border-radius: 5px;
  font-variant-numeric: tabular-nums;
  isolation: isolate;
}

.report-reach i {
  position: absolute;
  z-index: -1;
  top: 0;
  bottom: 0;
  left: 0;
  border-radius: 5px;
  background: var(--violet);
  opacity: .3;
}

.report-reach--1 i { opacity: .45; }
.report-reach--2 i { opacity: .6; }
.report-reach--3 i { opacity: .78; }
.report-reach--4 i { opacity: 1; }

@keyframes census-spin {
  to { transform: rotate(360deg); }
}

@keyframes rise-in {
  from { opacity: 0; transform: translateY(26px); }
  to { opacity: 1; transform: translateY(0); }
}

@keyframes fade-in {
  from { opacity: 0; }
  to { opacity: 1; }
}

@keyframes modal-content-in {
  from { opacity: 0; }
  to { opacity: 1; }
}

@keyframes card-float {
  0%,
  100% { transform: translateY(0); }
  50% { transform: translateY(-14px); }
}

@keyframes handle-guide {
  0%,
  100% {
    background-color: rgba(255, 255, 255, .05);
    border-color: rgba(255, 255, 255, .14);
    box-shadow: 0 0 0 0 rgba(183, 156, 255, 0);
  }
  50% {
    background-color: rgba(183, 156, 255, .1);
    border-color: rgba(183, 156, 255, .55);
    box-shadow:
      0 0 0 5px rgba(183, 156, 255, .12),
      0 0 24px rgba(183, 156, 255, .2);
  }
}

@keyframes card-marquee {
  to { transform: translateX(-33.333333%); }
}

@keyframes radar-in {
  from {
    opacity: 0;
    transform: scale(.4);
  }
  to {
    opacity: 1;
    transform: scale(1);
  }
}

.radar-in {
  transform-origin: center;
  animation: radar-in .9s cubic-bezier(.2, .8, .2, 1) .15s both;
}

@keyframes reveal-impact {
  0% { opacity: 0; transform: scale(.62); }
  10% { opacity: .64; transform: scale(.86); }
  27% { opacity: .28; }
  100% { opacity: 0; transform: scale(1.26); }
}

@keyframes reveal-charge {
  to { opacity: .5; letter-spacing: .4em; }
}

@keyframes reveal-trace {
  to { stroke-dashoffset: 0; }
}

@media (max-width: 900px) {
  .result-main {
    grid-template-columns: 1fr;
    gap: 38px;
    padding-block: 34px 70px;
  }

  .result-overview {
    gap: 18px;
  }

  .result-title-row h1 {
    max-width: 100%;
    white-space: normal;
  }

  .rating-radar {
    justify-content: center;
  }
}

@media (max-width: 767px) {
  .landing-main {
    grid-template-columns: 1fr;
    gap: 40px;
    padding-top: 44px;
  }
}

@media (max-width: 620px) {
  .site-header {
    min-height: 66px;
    padding-top: 14px;
  }

  .landing-main {
    padding-top: 34px;
  }

  .hero-copy h1 {
    font-size: clamp(42px, 14vw, 62px);
  }

  .hero-copy__lede {
    font-size: 16px;
  }

  .hero-actions {
    align-items: center;
  }

  .card-marquee {
    padding-bottom: 20px;
  }

  .modal-backdrop {
    align-items: end;
    padding: 0;
  }

  .modal {
    width: 100%;
    max-height: calc(100svh - 24px);
    border-radius: 22px 22px 0 0;
  }

  .settings-field {
    align-items: stretch;
    grid-template-columns: 1fr;
  }

  .settings-readout {
    text-align: left;
  }

  .running-actions {
    flex-wrap: wrap;
  }

  .running-heading {
    flex-wrap: nowrap;
    gap: 10px;
  }

  .running-heading h1 {
    font-size: clamp(50px, 17vw, 64px);
  }

  .running-heading__unit {
    font-size: 9px;
    letter-spacing: .06em;
  }

  .gpu-gauge {
    width: 112px;
    height: 90px;
  }

  .gpu-gauge svg {
    height: 70px;
  }

  /* Two truncated captions side by side would say nothing at this width; one per
     row still holds a fixed two-row height. */
  .mosaic-summary {
    grid-template-columns: minmax(0, 1fr);
  }

  .op-ticker {
    grid-template-columns: minmax(0, 1fr);
  }

  .op-ticker__primary {
    min-height: 72px;
  }

  .op-ticker__context {
    display: grid;
    align-items: center;
    gap: 14px;
    grid-template-columns: auto minmax(0, 1fr);
  }

  .op-ticker__history,
  .op-ticker__measures {
    display: flex;
    height: 16px;
    gap: 14px;
    margin-top: 0;
    overflow: hidden;
  }

  .op-ticker__history li,
  .op-ticker__measures li {
    flex: none;
    white-space: nowrap;
  }

  .op-ticker__history li > span:last-child {
    display: none;
  }

  .running-visible-note {
    width: 100%;
    margin-left: 0;
  }

  .running-details {
    grid-template-columns: 1fr;
  }

  .running-details article {
    padding-block: 8px;
    border-right: 0;
    border-bottom: 1px solid var(--line);
  }

  .result-title-row {
    align-items: flex-start;
    flex-direction: column;
  }

  .result-overview {
    grid-template-columns: 1fr;
  }

  .comparison-panel {
    align-items: stretch;
    flex-direction: column;
  }

  .tier-rail {
    min-width: 0;
    width: 100%;
  }

  .reveal-eyebrow {
    top: 8%;
    max-width: calc(100% - 32px);
    overflow: hidden;
    font-size: 9px;
    text-overflow: ellipsis;
  }

  .reveal-prompt {
    bottom: 20px;
  }

  .reveal-skip {
    top: max(16px, env(safe-area-inset-top));
    right: max(14px, env(safe-area-inset-right));
    bottom: auto;
    left: auto;
  }

  .reveal-sound {
    top: max(16px, env(safe-area-inset-top));
    left: max(14px, env(safe-area-inset-left));
    bottom: auto;
    right: auto;
  }
}

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

  .card-float,
  .card-marquee__track {
    animation: none;
  }

  .running-screen .census-spinner {
    animation: none !important;
    border-color: rgba(183, 156, 255, .35);
    border-top-color: var(--violet);
  }

  .running-screen .gpu-gauge__needle {
    transition: none !important;
  }

  .card-studio:has(.holo-card:hover)
    .handle-field:not(.is-filled):not(:focus-within) {
    background-color: rgba(183, 156, 255, .1);
    border-color: rgba(183, 156, 255, .55);
    box-shadow: 0 0 0 3px rgba(183, 156, 255, .12);
  }

  .reveal-prompt__trace[data-measured] rect {
    stroke-dashoffset: 0;
  }
}
