# WebVitalGauge

> A gauge for one Core Web Vital (LCP, INP, CLS, FCP, TTFB) with Google's good, needs-improvement and poor bands, the p75 value and the distribution of page loads.

Source: https://docs.nasaqui.com/components/web-vital-gauge

## Install

```bash
npx shadcn@latest add https://docs.nasaqui.com/r/web-vital-gauge.json
```

WebVitalGauge shows one metric at the 75th percentile of page loads, judged with Google's published thresholds: LCP 2.5 s / 4 s, INP 200 ms / 500 ms, CLS 0.1 / 0.25, FCP 1.8 s / 3 s and TTFB 0.8 s / 1.8 s. Good is at or below the first number, poor is above the second. The gauge, a rating label with an icon and a stacked bar of page loads by rating say the same thing three ways. The pure functions (`rateVital`, `passesCoreWebVitals`, …) are exported from the package too.

## When to use

- Real-user performance dashboards.
- Showing where a metric sits against Google's limits.

## When not to use

- Lab audits with a single 0 to 100 score: use [`Progress`](https://docs.nasaqui.com/components/progress).
- Trends: use [`TimeSeriesPanel`](https://docs.nasaqui.com/components/time-series-panel) with `referenceLines`.

## Import

```tsx
import { WebVitalGauge, WebVitalGaugeGrid } from "@fadymondy/nasaq/web";
```

## Quick start

```tsx
import { WebVitalGauge, WebVitalGaugeGrid } from "@fadymondy/nasaq/web";

export function Vitals() {
  return (
    <WebVitalGaugeGrid>
      <WebVitalGauge metric="LCP" value={2900} previous={3100} distribution={{ good: 0.58, needsImprovement: 0.28, poor: 0.14 }} />
      <WebVitalGauge metric="INP" value={182} />
      <WebVitalGauge metric="CLS" value={0.08} />
    </WebVitalGaugeGrid>
  );
}
```

## Anatomy

```
WebVitalGauge          data-slot="web-vital-gauge"  data-rating="good|needs-improvement|poor"
  arc                  three bands and a needle (role="img" with a text summary)
  value + rating       Status with an icon
  distribution bar     good / needs improvement / poor share of page loads
WebVitalGaugeGrid      data-slot="web-vital-gauge-grid"
```

## API

### WebVitalGauge

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `metric` | `"LCP" \| "INP" \| "CLS" \| "FCP" \| "TTFB"` | required | Which vital. |
| `value` | `number` | none | The p75 in milliseconds (a plain score for CLS). Omit to show "No data". |
| `previous` | `number` | none | The p75 for the previous period; shows the change (lower is better). |
| `distribution` | `VitalDistribution` | none | Share of page loads per rating: `{ good, needsImprovement, poor }`, counts or fractions. |
| `onSelect` | `(metric) => void` | none | Makes the card a button, for choosing the metric a chart shows. |
| `selected` | `boolean` | `false` | Marks the card as chosen. |
| `className` | `string` | none | Extra classes on the root. |
| `labels` | `Partial<WebVitalGaugeLabels>` | none | Replace any built-in English or Arabic string. |

### formatVital

`formatVital(metric, value, locale)` returns `"2.9 s"`, `"182 ms"` or `"0.08"` (Arabic units "ث" and "مللي ث").



### Math helpers

`VITAL_THRESHOLDS`, `WEB_VITAL_IDS`, `rateVital(metric, value)`, `gaugeFraction`, `vitalBands`, `vitalDisplay`, `normalizeDistribution`, `passesCoreWebVitals(p75)` and `worstRating(ratings)` are exported for your own logic.



## Examples

Selectable gauges:

```tsx
import { WEB_VITAL_IDS, WebVitalGauge, WebVitalGaugeGrid, type WebVitalId } from "@fadymondy/nasaq/web";
import { useState } from "react";

export function Pick({ p75 }: { p75: Record<WebVitalId, number> }) {
  const [sel, setSel] = useState<WebVitalId>("LCP");
  return (
    <WebVitalGaugeGrid>
      {WEB_VITAL_IDS.map((id) => <WebVitalGauge key={id} metric={id} value={p75[id]} selected={sel === id} onSelect={setSel} />)}
    </WebVitalGaugeGrid>
  );
}
```

Rate a value yourself:

```tsx
import { passesCoreWebVitals, rateVital } from "@fadymondy/nasaq/web";

export const rating = rateVital("LCP", 2500); // "good"
export const passes = passesCoreWebVitals({ LCP: 2400, INP: 190, CLS: 0.09 }); // true
```

## Accessibility

The arc is an image with a text alternative giving the metric, the value and the rating. The rating is written out with an icon, so colour is never the only signal. With `onSelect` the card is a button with `aria-pressed`, reached with Tab and activated with Enter or Space.

## RTL & i18n

- The gauge is a semicircle read from the inline start: good sits at the start in both directions.
- Values and units are bidi-isolated; Arabic units are "ث" and "مللي ث".
- The card text is localised through `labels`.

## Styling & tokens

- Colours come from tokens (`--primary`, `--nq-success`, `--nq-warning`, `--nq-danger`, `--nq-tag-*`); never pass raw hex.
- Bands use `--nq-success`, `--nq-warning` and `--nq-danger`.

## Do / Don't

- Do pass the 75th percentile, which is what Google's thresholds judge.
- Do pass CLS as a plain score.
- Don't pass an average; it hides the slow tail.

## Related

- [`time-series-panel`](https://docs.nasaqui.com/components/time-series-panel)
- [`web-vitals-page`](https://docs.nasaqui.com/components/web-vitals-page)
- [`status`](https://docs.nasaqui.com/components/status)

## Lab

https://docs.nasaqui.com/?path=/docs/components-monitoring-web-vital-gauge--docs

## Code

### React

```tsx
import { WebVitalGauge, WebVitalGaugeGrid } from "@fadymondy/nasaq/web";

export function Vitals() {
  return (
    <WebVitalGaugeGrid>
      <WebVitalGauge metric="LCP" value={2900} previous={3100} distribution={{ good: 0.58, needsImprovement: 0.28, poor: 0.14 }} />
      <WebVitalGauge metric="INP" value={182} />
      <WebVitalGauge metric="CLS" value={0.08} />
    </WebVitalGaugeGrid>
  );
}
```

### shadcn

```tsx
import { WebVitalGauge, WebVitalGaugeGrid } from "@/components/ui/web-vital-gauge";

export function Vitals() {
  return (
    <WebVitalGaugeGrid>
      <WebVitalGauge metric="LCP" value={2900} previous={3100} distribution={{ good: 0.58, needsImprovement: 0.28, poor: 0.14 }} />
      <WebVitalGauge metric="INP" value={182} />
      <WebVitalGauge metric="CLS" value={0.08} />
    </WebVitalGaugeGrid>
  );
}
```

### Vue

```vue
<script setup lang="ts">
import { NqWebVitalGauge, NqWebVitalGaugeGrid } from "@fadymondy/nasaq/vue";
</script>

<template>
  <NqWebVitalGaugeGrid>
    <NqWebVitalGauge metric="LCP" :value="2900" :previous="3100" :distribution="{ good: 0.58, needsImprovement: 0.28, poor: 0.14 }" />
    <NqWebVitalGauge metric="INP" :value="182" />
    <NqWebVitalGauge metric="CLS" :value="0.08" />
  </NqWebVitalGaugeGrid>
</template>
```

### Blade

```blade
<x-nq::web-vital-gauge.grid>
    <x-nq::web-vital-gauge metric="LCP" :value="2900" :previous="3100" :distribution="['good' => 0.58, 'needsImprovement' => 0.28, 'poor' => 0.14]" />
    <x-nq::web-vital-gauge metric="INP" :value="182" />
    <x-nq::web-vital-gauge metric="CLS" :value="0.08" />
</x-nq::web-vital-gauge.grid>

<x-nq::web-vital-gauge.grid selectable selected="LCP">
    <x-nq::web-vital-gauge selectable metric="LCP" :value="2900" />
    <x-nq::web-vital-gauge selectable metric="INP" :value="182" />
    <x-nq::web-vital-gauge selectable metric="CLS" :value="0.08" />
</x-nq::web-vital-gauge.grid>
```

### HTML + Alpine

```html
<div data-slot="web-vital-gauge-grid"  class="grid grid-cols-[repeat(auto-fit,minmax(min(100%,12.5rem),1fr))] gap-3"><div data-slot="web-vital-gauge" data-metric="LCP" data-rating="needs-improvement" class="flex flex-col rounded-card border border-border bg-card text-card-foreground h-full gap-3 px-4 py-4"><div class="flex items-start justify-between gap-2">
        <div class="flex min-w-0 flex-col">
            <div class="flex items-center gap-2">
                <span class="text-label text-foreground" dir="ltr">LCP</span>
                <span class="rounded-control bg-secondary px-1.5 py-0.5 text-caption text-muted-foreground">Core</span>            </div>
            <span class="truncate text-caption text-muted-foreground">Largest Contentful Paint</span>
        </div>
        <span data-slot="status" data-tone="warning" class="inline-flex min-w-0 items-center gap-1.5 text-nq-warning-text shrink-0 text-caption">
            <svg aria-hidden="true" class="size-3.5 shrink-0 text-nq-warning-text" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
  <circle cx="12" cy="12" r="10"/>
  <line x1="12" x2="12" y1="8" y2="12"/>
  <line x1="12" x2="12.01" y1="16" y2="16"/>
</svg>        <span class="truncate"  title="Needs improvement" >Needs improvement</span>
</span>
    </div>
    <div class="relative mx-auto w-full max-w-56">
        <svg viewBox="0 0 200 116" role="img" aria-label="Largest Contentful Paint: 2.9 s, Needs improvement" class="block w-full rtl:-scale-x-100">
            <path d="M 20.00 100.00 A 80 80 0 0 1 180.00 100.00" fill="none" stroke="var(--nq-surface-soft)" stroke-width="16" stroke-linecap="butt" />
            <path d="M 20.00 100.00 A 80 80 0 0 1 79.29 22.73" fill="none" stroke="var(--nq-success)" stroke-width="14" />
            <path d="M 79.29 22.73 A 80 80 0 0 1 140.00 30.72" fill="none" stroke="var(--nq-warning)" stroke-width="14" />
            <path d="M 140.00 30.72 A 80 80 0 0 1 180.00 100.00" fill="none" stroke="var(--nq-danger)" stroke-width="14" />
                            <g>
                    <circle cx="95.8131" cy="20.1096" r="9" fill="var(--card)" stroke="var(--foreground)" stroke-width="2.5" />
                    <circle cx="95.8131" cy="20.1096" r="3" fill="var(--nq-warning)" />
                </g>
                    </svg>
        <div class="pointer-events-none absolute inset-x-0 bottom-0 flex flex-col items-center leading-tight">
            <span data-slot="web-vital-value" class="text-h2 text-foreground tabular-nums" dir="ltr">2.9 s</span>
            <span class="text-caption text-muted-foreground">75th percentile</span>
        </div>
    </div>
            <p class="flex items-center justify-center gap-1.5 text-caption">
            <svg aria-hidden="true" class="size-3.5 text-nq-success-text rtl:-scale-x-100" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
  <path d="M16 17h6v-6"/>
  <path d="m22 17-8.5-8.5-5 5L2 7"/>
</svg>            <bdi data-slot="num" data-numeric="" class="tabular-nums text-label text-nq-success-text">-6.5%</bdi>
            <span class="text-muted-foreground">vs previous period</span>
        </p>
    <ul class="grid gap-1 text-caption text-muted-foreground" aria-label="How fast the main content appears">
        <li class="flex items-center justify-between gap-2">
            <span data-slot="status" data-tone="success" class="inline-flex min-w-0 items-center gap-1.5 text-body-sm text-foreground shrink-0 whitespace-nowrap">
            <svg aria-hidden="true" class="size-3.5 shrink-0 text-nq-success-text" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
  <circle cx="12" cy="12" r="10"/>
  <path d="m9 12 2 2 4-4"/>
</svg>        <span class="truncate"  title="Good" >Good</span>
</span>
            <bdi dir="ltr" class="text-end">up to 2.5 s</bdi>
        </li>
        <li class="flex items-center justify-between gap-2">
            <span data-slot="status" data-tone="warning" class="inline-flex min-w-0 items-center gap-1.5 text-body-sm text-foreground shrink-0 whitespace-nowrap">
            <svg aria-hidden="true" class="size-3.5 shrink-0 text-nq-warning-text" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
  <circle cx="12" cy="12" r="10"/>
  <line x1="12" x2="12" y1="8" y2="12"/>
  <line x1="12" x2="12.01" y1="16" y2="16"/>
</svg>        <span class="truncate"  title="Needs improvement" >Needs improvement</span>
</span>
            <bdi dir="ltr" class="text-end">2.5 s to 4 s</bdi>
        </li>
        <li class="flex items-center justify-between gap-2">
            <span data-slot="status" data-tone="danger" class="inline-flex min-w-0 items-center gap-1.5 text-body-sm text-foreground shrink-0 whitespace-nowrap">
            <svg aria-hidden="true" class="size-3.5 shrink-0 text-nq-danger-text" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
  <circle cx="12" cy="12" r="10"/>
  <path d="m15 9-6 6"/>
  <path d="m9 9 6 6"/>
</svg>        <span class="truncate"  title="Poor" >Poor</span>
</span>
            <bdi dir="ltr" class="text-end">over 4 s</bdi>
        </li>
    </ul>
            <div data-slot="web-vital-distribution" class="flex flex-col gap-1.5">
            <span class="text-caption text-muted-foreground">Page loads by rating</span>
            <div role="img" aria-label="Page loads by rating: Good 58%, Needs improvement 28%, Poor 14%" class="flex h-2 w-full gap-0.5 overflow-hidden rounded-full">
                <span class="block h-full bg-nq-success" style="width: 58%"></span>                <span class="block h-full bg-nq-warning" style="width: 28%"></span>                <span class="block h-full bg-nq-danger" style="width: 14%"></span>            </div>
            <div class="flex justify-between text-caption tabular-nums text-muted-foreground">
                <bdi>58%</bdi>
                <bdi>28%</bdi>
                <bdi>14%</bdi>
            </div>
        </div></div>
    <div data-slot="web-vital-gauge" data-metric="INP" data-rating="good" class="flex flex-col rounded-card border border-border bg-card text-card-foreground h-full gap-3 px-4 py-4"><div class="flex items-start justify-between gap-2">
        <div class="flex min-w-0 flex-col">
            <div class="flex items-center gap-2">
                <span class="text-label text-foreground" dir="ltr">INP</span>
                <span class="rounded-control bg-secondary px-1.5 py-0.5 text-caption text-muted-foreground">Core</span>            </div>
            <span class="truncate text-caption text-muted-foreground">Interaction to Next Paint</span>
        </div>
        <span data-slot="status" data-tone="success" class="inline-flex min-w-0 items-center gap-1.5 text-nq-success-text shrink-0 text-caption">
            <svg aria-hidden="true" class="size-3.5 shrink-0 text-nq-success-text" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
  <circle cx="12" cy="12" r="10"/>
  <path d="m9 12 2 2 4-4"/>
</svg>        <span class="truncate"  title="Good" >Good</span>
</span>
    </div>
    <div class="relative mx-auto w-full max-w-56">
        <svg viewBox="0 0 200 116" role="img" aria-label="Interaction to Next Paint: 182 ms, Good" class="block w-full rtl:-scale-x-100">
            <path d="M 20.00 100.00 A 80 80 0 0 1 180.00 100.00" fill="none" stroke="var(--nq-surface-soft)" stroke-width="16" stroke-linecap="butt" />
            <path d="M 20.00 100.00 A 80 80 0 0 1 46.47 40.55" fill="none" stroke="var(--nq-success)" stroke-width="14" />
            <path d="M 46.47 40.55 A 80 80 0 0 1 140.00 30.72" fill="none" stroke="var(--nq-warning)" stroke-width="14" />
            <path d="M 140.00 30.72 A 80 80 0 0 1 180.00 100.00" fill="none" stroke="var(--nq-danger)" stroke-width="14" />
                            <g>
                    <circle cx="42.1433" cy="44.7496" r="9" fill="var(--card)" stroke="var(--foreground)" stroke-width="2.5" />
                    <circle cx="42.1433" cy="44.7496" r="3" fill="var(--nq-success)" />
                </g>
                    </svg>
        <div class="pointer-events-none absolute inset-x-0 bottom-0 flex flex-col items-center leading-tight">
            <span data-slot="web-vital-value" class="text-h2 text-foreground tabular-nums" dir="ltr">182 ms</span>
            <span class="text-caption text-muted-foreground">75th percentile</span>
        </div>
    </div>
    <ul class="grid gap-1 text-caption text-muted-foreground" aria-label="How quickly the page responds to input">
        <li class="flex items-center justify-between gap-2">
            <span data-slot="status" data-tone="success" class="inline-flex min-w-0 items-center gap-1.5 text-body-sm text-foreground shrink-0 whitespace-nowrap">
            <svg aria-hidden="true" class="size-3.5 shrink-0 text-nq-success-text" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
  <circle cx="12" cy="12" r="10"/>
  <path d="m9 12 2 2 4-4"/>
</svg>        <span class="truncate"  title="Good" >Good</span>
</span>
            <bdi dir="ltr" class="text-end">up to 200 ms</bdi>
        </li>
        <li class="flex items-center justify-between gap-2">
            <span data-slot="status" data-tone="warning" class="inline-flex min-w-0 items-center gap-1.5 text-body-sm text-foreground shrink-0 whitespace-nowrap">
            <svg aria-hidden="true" class="size-3.5 shrink-0 text-nq-warning-text" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
  <circle cx="12" cy="12" r="10"/>
  <line x1="12" x2="12" y1="8" y2="12"/>
  <line x1="12" x2="12.01" y1="16" y2="16"/>
</svg>        <span class="truncate"  title="Needs improvement" >Needs improvement</span>
</span>
            <bdi dir="ltr" class="text-end">200 ms to 500 ms</bdi>
        </li>
        <li class="flex items-center justify-between gap-2">
            <span data-slot="status" data-tone="danger" class="inline-flex min-w-0 items-center gap-1.5 text-body-sm text-foreground shrink-0 whitespace-nowrap">
            <svg aria-hidden="true" class="size-3.5 shrink-0 text-nq-danger-text" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
  <circle cx="12" cy="12" r="10"/>
  <path d="m15 9-6 6"/>
  <path d="m9 9 6 6"/>
</svg>        <span class="truncate"  title="Poor" >Poor</span>
</span>
            <bdi dir="ltr" class="text-end">over 500 ms</bdi>
        </li>
    </ul></div>
    <div data-slot="web-vital-gauge" data-metric="CLS" data-rating="good" class="flex flex-col rounded-card border border-border bg-card text-card-foreground h-full gap-3 px-4 py-4"><div class="flex items-start justify-between gap-2">
        <div class="flex min-w-0 flex-col">
            <div class="flex items-center gap-2">
                <span class="text-label text-foreground" dir="ltr">CLS</span>
                <span class="rounded-control bg-secondary px-1.5 py-0.5 text-caption text-muted-foreground">Core</span>            </div>
            <span class="truncate text-caption text-muted-foreground">Cumulative Layout Shift</span>
        </div>
        <span data-slot="status" data-tone="success" class="inline-flex min-w-0 items-center gap-1.5 text-nq-success-text shrink-0 text-caption">
            <svg aria-hidden="true" class="size-3.5 shrink-0 text-nq-success-text" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
  <circle cx="12" cy="12" r="10"/>
  <path d="m9 12 2 2 4-4"/>
</svg>        <span class="truncate"  title="Good" >Good</span>
</span>
    </div>
    <div class="relative mx-auto w-full max-w-56">
        <svg viewBox="0 0 200 116" role="img" aria-label="Cumulative Layout Shift: 0.08, Good" class="block w-full rtl:-scale-x-100">
            <path d="M 20.00 100.00 A 80 80 0 0 1 180.00 100.00" fill="none" stroke="var(--nq-surface-soft)" stroke-width="16" stroke-linecap="butt" />
            <path d="M 20.00 100.00 A 80 80 0 0 1 46.47 40.55" fill="none" stroke="var(--nq-success)" stroke-width="14" />
            <path d="M 46.47 40.55 A 80 80 0 0 1 140.00 30.72" fill="none" stroke="var(--nq-warning)" stroke-width="14" />
            <path d="M 140.00 30.72 A 80 80 0 0 1 180.00 100.00" fill="none" stroke="var(--nq-danger)" stroke-width="14" />
                            <g>
                    <circle cx="37.3045" cy="50.3082" r="9" fill="var(--card)" stroke="var(--foreground)" stroke-width="2.5" />
                    <circle cx="37.3045" cy="50.3082" r="3" fill="var(--nq-success)" />
                </g>
                    </svg>
        <div class="pointer-events-none absolute inset-x-0 bottom-0 flex flex-col items-center leading-tight">
            <span data-slot="web-vital-value" class="text-h2 text-foreground tabular-nums" dir="ltr">0.08</span>
            <span class="text-caption text-muted-foreground">75th percentile</span>
        </div>
    </div>
    <ul class="grid gap-1 text-caption text-muted-foreground" aria-label="How much the layout jumps while loading">
        <li class="flex items-center justify-between gap-2">
            <span data-slot="status" data-tone="success" class="inline-flex min-w-0 items-center gap-1.5 text-body-sm text-foreground shrink-0 whitespace-nowrap">
            <svg aria-hidden="true" class="size-3.5 shrink-0 text-nq-success-text" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
  <circle cx="12" cy="12" r="10"/>
  <path d="m9 12 2 2 4-4"/>
</svg>        <span class="truncate"  title="Good" >Good</span>
</span>
            <bdi dir="ltr" class="text-end">up to 0.1</bdi>
        </li>
        <li class="flex items-center justify-between gap-2">
            <span data-slot="status" data-tone="warning" class="inline-flex min-w-0 items-center gap-1.5 text-body-sm text-foreground shrink-0 whitespace-nowrap">
            <svg aria-hidden="true" class="size-3.5 shrink-0 text-nq-warning-text" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
  <circle cx="12" cy="12" r="10"/>
  <line x1="12" x2="12" y1="8" y2="12"/>
  <line x1="12" x2="12.01" y1="16" y2="16"/>
</svg>        <span class="truncate"  title="Needs improvement" >Needs improvement</span>
</span>
            <bdi dir="ltr" class="text-end">0.1 to 0.25</bdi>
        </li>
        <li class="flex items-center justify-between gap-2">
            <span data-slot="status" data-tone="danger" class="inline-flex min-w-0 items-center gap-1.5 text-body-sm text-foreground shrink-0 whitespace-nowrap">
            <svg aria-hidden="true" class="size-3.5 shrink-0 text-nq-danger-text" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
  <circle cx="12" cy="12" r="10"/>
  <path d="m15 9-6 6"/>
  <path d="m9 9 6 6"/>
</svg>        <span class="truncate"  title="Poor" >Poor</span>
</span>
            <bdi dir="ltr" class="text-end">over 0.25</bdi>
        </li>
    </ul></div></div>
<div data-slot="web-vital-gauge-grid"  x-data="nqMetricTiles('LCP')"  class="grid grid-cols-[repeat(auto-fit,minmax(min(100%,12.5rem),1fr))] gap-3"><button type="button" x-bind:aria-pressed="String(selected === 'LCP')" x-on:click="select('LCP')" class="rounded-card text-start outline-none focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-nq-focus">
<div data-slot="web-vital-gauge" data-metric="LCP" data-rating="needs-improvement" x-bind:class="selected === `LCP` ? `border-primary ring-1 ring-primary` : ``" class="flex flex-col rounded-card border border-border bg-card text-card-foreground h-full gap-3 px-4 py-4"><div class="flex items-start justify-between gap-2">
        <div class="flex min-w-0 flex-col">
            <div class="flex items-center gap-2">
                <span class="text-label text-foreground" dir="ltr">LCP</span>
                <span class="rounded-control bg-secondary px-1.5 py-0.5 text-caption text-muted-foreground">Core</span>            </div>
            <span class="truncate text-caption text-muted-foreground">Largest Contentful Paint</span>
        </div>
        <span data-slot="status" data-tone="warning" class="inline-flex min-w-0 items-center gap-1.5 text-nq-warning-text shrink-0 text-caption">
            <svg aria-hidden="true" class="size-3.5 shrink-0 text-nq-warning-text" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
  <circle cx="12" cy="12" r="10"/>
  <line x1="12" x2="12" y1="8" y2="12"/>
  <line x1="12" x2="12.01" y1="16" y2="16"/>
</svg>        <span class="truncate"  title="Needs improvement" >Needs improvement</span>
</span>
    </div>
    <div class="relative mx-auto w-full max-w-56">
        <svg viewBox="0 0 200 116" role="img" aria-label="Largest Contentful Paint: 2.9 s, Needs improvement" class="block w-full rtl:-scale-x-100">
            <path d="M 20.00 100.00 A 80 80 0 0 1 180.00 100.00" fill="none" stroke="var(--nq-surface-soft)" stroke-width="16" stroke-linecap="butt" />
            <path d="M 20.00 100.00 A 80 80 0 0 1 79.29 22.73" fill="none" stroke="var(--nq-success)" stroke-width="14" />
            <path d="M 79.29 22.73 A 80 80 0 0 1 140.00 30.72" fill="none" stroke="var(--nq-warning)" stroke-width="14" />
            <path d="M 140.00 30.72 A 80 80 0 0 1 180.00 100.00" fill="none" stroke="var(--nq-danger)" stroke-width="14" />
                            <g>
                    <circle cx="95.8131" cy="20.1096" r="9" fill="var(--card)" stroke="var(--foreground)" stroke-width="2.5" />
                    <circle cx="95.8131" cy="20.1096" r="3" fill="var(--nq-warning)" />
                </g>
                    </svg>
        <div class="pointer-events-none absolute inset-x-0 bottom-0 flex flex-col items-center leading-tight">
            <span data-slot="web-vital-value" class="text-h2 text-foreground tabular-nums" dir="ltr">2.9 s</span>
            <span class="text-caption text-muted-foreground">75th percentile</span>
        </div>
    </div>
    <ul class="grid gap-1 text-caption text-muted-foreground" aria-label="How fast the main content appears">
        <li class="flex items-center justify-between gap-2">
            <span data-slot="status" data-tone="success" class="inline-flex min-w-0 items-center gap-1.5 text-body-sm text-foreground shrink-0 whitespace-nowrap">
            <svg aria-hidden="true" class="size-3.5 shrink-0 text-nq-success-text" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
  <circle cx="12" cy="12" r="10"/>
  <path d="m9 12 2 2 4-4"/>
</svg>        <span class="truncate"  title="Good" >Good</span>
</span>
            <bdi dir="ltr" class="text-end">up to 2.5 s</bdi>
        </li>
        <li class="flex items-center justify-between gap-2">
            <span data-slot="status" data-tone="warning" class="inline-flex min-w-0 items-center gap-1.5 text-body-sm text-foreground shrink-0 whitespace-nowrap">
            <svg aria-hidden="true" class="size-3.5 shrink-0 text-nq-warning-text" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
  <circle cx="12" cy="12" r="10"/>
  <line x1="12" x2="12" y1="8" y2="12"/>
  <line x1="12" x2="12.01" y1="16" y2="16"/>
</svg>        <span class="truncate"  title="Needs improvement" >Needs improvement</span>
</span>
            <bdi dir="ltr" class="text-end">2.5 s to 4 s</bdi>
        </li>
        <li class="flex items-center justify-between gap-2">
            <span data-slot="status" data-tone="danger" class="inline-flex min-w-0 items-center gap-1.5 text-body-sm text-foreground shrink-0 whitespace-nowrap">
            <svg aria-hidden="true" class="size-3.5 shrink-0 text-nq-danger-text" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
  <circle cx="12" cy="12" r="10"/>
  <path d="m15 9-6 6"/>
  <path d="m9 9 6 6"/>
</svg>        <span class="truncate"  title="Poor" >Poor</span>
</span>
            <bdi dir="ltr" class="text-end">over 4 s</bdi>
        </li>
    </ul></div>
    </button>
    <button type="button" x-bind:aria-pressed="String(selected === 'INP')" x-on:click="select('INP')" class="rounded-card text-start outline-none focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-nq-focus">
<div data-slot="web-vital-gauge" data-metric="INP" data-rating="good" x-bind:class="selected === `INP` ? `border-primary ring-1 ring-primary` : ``" class="flex flex-col rounded-card border border-border bg-card text-card-foreground h-full gap-3 px-4 py-4"><div class="flex items-start justify-between gap-2">
        <div class="flex min-w-0 flex-col">
            <div class="flex items-center gap-2">
                <span class="text-label text-foreground" dir="ltr">INP</span>
                <span class="rounded-control bg-secondary px-1.5 py-0.5 text-caption text-muted-foreground">Core</span>            </div>
            <span class="truncate text-caption text-muted-foreground">Interaction to Next Paint</span>
        </div>
        <span data-slot="status" data-tone="success" class="inline-flex min-w-0 items-center gap-1.5 text-nq-success-text shrink-0 text-caption">
            <svg aria-hidden="true" class="size-3.5 shrink-0 text-nq-success-text" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
  <circle cx="12" cy="12" r="10"/>
  <path d="m9 12 2 2 4-4"/>
</svg>        <span class="truncate"  title="Good" >Good</span>
</span>
    </div>
    <div class="relative mx-auto w-full max-w-56">
        <svg viewBox="0 0 200 116" role="img" aria-label="Interaction to Next Paint: 182 ms, Good" class="block w-full rtl:-scale-x-100">
            <path d="M 20.00 100.00 A 80 80 0 0 1 180.00 100.00" fill="none" stroke="var(--nq-surface-soft)" stroke-width="16" stroke-linecap="butt" />
            <path d="M 20.00 100.00 A 80 80 0 0 1 46.47 40.55" fill="none" stroke="var(--nq-success)" stroke-width="14" />
            <path d="M 46.47 40.55 A 80 80 0 0 1 140.00 30.72" fill="none" stroke="var(--nq-warning)" stroke-width="14" />
            <path d="M 140.00 30.72 A 80 80 0 0 1 180.00 100.00" fill="none" stroke="var(--nq-danger)" stroke-width="14" />
                            <g>
                    <circle cx="42.1433" cy="44.7496" r="9" fill="var(--card)" stroke="var(--foreground)" stroke-width="2.5" />
                    <circle cx="42.1433" cy="44.7496" r="3" fill="var(--nq-success)" />
                </g>
                    </svg>
        <div class="pointer-events-none absolute inset-x-0 bottom-0 flex flex-col items-center leading-tight">
            <span data-slot="web-vital-value" class="text-h2 text-foreground tabular-nums" dir="ltr">182 ms</span>
            <span class="text-caption text-muted-foreground">75th percentile</span>
        </div>
    </div>
    <ul class="grid gap-1 text-caption text-muted-foreground" aria-label="How quickly the page responds to input">
        <li class="flex items-center justify-between gap-2">
            <span data-slot="status" data-tone="success" class="inline-flex min-w-0 items-center gap-1.5 text-body-sm text-foreground shrink-0 whitespace-nowrap">
            <svg aria-hidden="true" class="size-3.5 shrink-0 text-nq-success-text" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
  <circle cx="12" cy="12" r="10"/>
  <path d="m9 12 2 2 4-4"/>
</svg>        <span class="truncate"  title="Good" >Good</span>
</span>
            <bdi dir="ltr" class="text-end">up to 200 ms</bdi>
        </li>
        <li class="flex items-center justify-between gap-2">
            <span data-slot="status" data-tone="warning" class="inline-flex min-w-0 items-center gap-1.5 text-body-sm text-foreground shrink-0 whitespace-nowrap">
            <svg aria-hidden="true" class="size-3.5 shrink-0 text-nq-warning-text" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
  <circle cx="12" cy="12" r="10"/>
  <line x1="12" x2="12" y1="8" y2="12"/>
  <line x1="12" x2="12.01" y1="16" y2="16"/>
</svg>        <span class="truncate"  title="Needs improvement" >Needs improvement</span>
</span>
            <bdi dir="ltr" class="text-end">200 ms to 500 ms</bdi>
        </li>
        <li class="flex items-center justify-between gap-2">
            <span data-slot="status" data-tone="danger" class="inline-flex min-w-0 items-center gap-1.5 text-body-sm text-foreground shrink-0 whitespace-nowrap">
            <svg aria-hidden="true" class="size-3.5 shrink-0 text-nq-danger-text" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
  <circle cx="12" cy="12" r="10"/>
  <path d="m15 9-6 6"/>
  <path d="m9 9 6 6"/>
</svg>        <span class="truncate"  title="Poor" >Poor</span>
</span>
            <bdi dir="ltr" class="text-end">over 500 ms</bdi>
        </li>
    </ul></div>
    </button>
    <button type="button" x-bind:aria-pressed="String(selected === 'CLS')" x-on:click="select('CLS')" class="rounded-card text-start outline-none focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-nq-focus">
<div data-slot="web-vital-gauge" data-metric="CLS" data-rating="good" x-bind:class="selected === `CLS` ? `border-primary ring-1 ring-primary` : ``" class="flex flex-col rounded-card border border-border bg-card text-card-foreground h-full gap-3 px-4 py-4"><div class="flex items-start justify-between gap-2">
        <div class="flex min-w-0 flex-col">
            <div class="flex items-center gap-2">
                <span class="text-label text-foreground" dir="ltr">CLS</span>
                <span class="rounded-control bg-secondary px-1.5 py-0.5 text-caption text-muted-foreground">Core</span>            </div>
            <span class="truncate text-caption text-muted-foreground">Cumulative Layout Shift</span>
        </div>
        <span data-slot="status" data-tone="success" class="inline-flex min-w-0 items-center gap-1.5 text-nq-success-text shrink-0 text-caption">
            <svg aria-hidden="true" class="size-3.5 shrink-0 text-nq-success-text" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
  <circle cx="12" cy="12" r="10"/>
  <path d="m9 12 2 2 4-4"/>
</svg>        <span class="truncate"  title="Good" >Good</span>
</span>
    </div>
    <div class="relative mx-auto w-full max-w-56">
        <svg viewBox="0 0 200 116" role="img" aria-label="Cumulative Layout Shift: 0.08, Good" class="block w-full rtl:-scale-x-100">
            <path d="M 20.00 100.00 A 80 80 0 0 1 180.00 100.00" fill="none" stroke="var(--nq-surface-soft)" stroke-width="16" stroke-linecap="butt" />
            <path d="M 20.00 100.00 A 80 80 0 0 1 46.47 40.55" fill="none" stroke="var(--nq-success)" stroke-width="14" />
            <path d="M 46.47 40.55 A 80 80 0 0 1 140.00 30.72" fill="none" stroke="var(--nq-warning)" stroke-width="14" />
            <path d="M 140.00 30.72 A 80 80 0 0 1 180.00 100.00" fill="none" stroke="var(--nq-danger)" stroke-width="14" />
                            <g>
                    <circle cx="37.3045" cy="50.3082" r="9" fill="var(--card)" stroke="var(--foreground)" stroke-width="2.5" />
                    <circle cx="37.3045" cy="50.3082" r="3" fill="var(--nq-success)" />
                </g>
                    </svg>
        <div class="pointer-events-none absolute inset-x-0 bottom-0 flex flex-col items-center leading-tight">
            <span data-slot="web-vital-value" class="text-h2 text-foreground tabular-nums" dir="ltr">0.08</span>
            <span class="text-caption text-muted-foreground">75th percentile</span>
        </div>
    </div>
    <ul class="grid gap-1 text-caption text-muted-foreground" aria-label="How much the layout jumps while loading">
        <li class="flex items-center justify-between gap-2">
            <span data-slot="status" data-tone="success" class="inline-flex min-w-0 items-center gap-1.5 text-body-sm text-foreground shrink-0 whitespace-nowrap">
            <svg aria-hidden="true" class="size-3.5 shrink-0 text-nq-success-text" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
  <circle cx="12" cy="12" r="10"/>
  <path d="m9 12 2 2 4-4"/>
</svg>        <span class="truncate"  title="Good" >Good</span>
</span>
            <bdi dir="ltr" class="text-end">up to 0.1</bdi>
        </li>
        <li class="flex items-center justify-between gap-2">
            <span data-slot="status" data-tone="warning" class="inline-flex min-w-0 items-center gap-1.5 text-body-sm text-foreground shrink-0 whitespace-nowrap">
            <svg aria-hidden="true" class="size-3.5 shrink-0 text-nq-warning-text" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
  <circle cx="12" cy="12" r="10"/>
  <line x1="12" x2="12" y1="8" y2="12"/>
  <line x1="12" x2="12.01" y1="16" y2="16"/>
</svg>        <span class="truncate"  title="Needs improvement" >Needs improvement</span>
</span>
            <bdi dir="ltr" class="text-end">0.1 to 0.25</bdi>
        </li>
        <li class="flex items-center justify-between gap-2">
            <span data-slot="status" data-tone="danger" class="inline-flex min-w-0 items-center gap-1.5 text-body-sm text-foreground shrink-0 whitespace-nowrap">
            <svg aria-hidden="true" class="size-3.5 shrink-0 text-nq-danger-text" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
  <circle cx="12" cy="12" r="10"/>
  <path d="m15 9-6 6"/>
  <path d="m9 9 6 6"/>
</svg>        <span class="truncate"  title="Poor" >Poor</span>
</span>
            <bdi dir="ltr" class="text-end">over 0.25</bdi>
        </li>
    </ul></div>
    </button></div>
```
