# Engine Card

> One Health Debug protocol engine's live state as a card, with a state badge, the engine's readout and its log action. Seven engines, one component.

Source: https://docs.nasaqui.com/components/engine-card

## Install

```bash
npx shadcn@latest add https://docs.nasaqui.com/r/engine-card.json
```

A card that shows what one protocol engine says right now. The server decides the state; the card draws it and
never re-derives a rule. It covers seven engines through one discriminated `EngineSnapshot`: hydration, caffeine
block, GERD window, medication grace, trigger families, cycle and contraceptive.

Two opinions are built in. A state always shows an icon and words next to its colour. An engine that has not
enough data says so and shows nothing, instead of guessing.

## When to use

- A dashboard of the protocol engines, one card each.
- Anywhere a single engine's state, countdown and log action belong together.

## When not to use

- A per-day summary of what was logged: use [`DailySummary`](https://docs.nasaqui.com/components/daily-summary).
- An engine's history and record: use [`EngineDetails`](https://docs.nasaqui.com/components/engine-details).
- A number that is not a protocol engine: use [`StatCard`](https://docs.nasaqui.com/components/stat-card).

## Import

```tsx
import { EngineCard, EngineCardGrid } from "@fadymondy/nasaq/web";
// inside this monorepo: "@nasaq/web"
```

## Quick start

```tsx
import { EngineCard, EngineCardGrid, type EngineSnapshot } from "@fadymondy/nasaq/web";

const hydration: EngineSnapshot = {
  engine: "hydration",
  state: "idle",
  totalMl: 1500,
  dailyCapMl: 5000,
  unitMl: 250,
  unitsLogged: 6,
  unitsTotal: 20,
};

export function Today() {
  return (
    <EngineCardGrid>
      <EngineCard
        snapshot={hydration}
        detailHref="/health/hydration"
        onAction={async (action) => {
          const res = await fetch("/api/engines/log", { method: "POST", body: JSON.stringify(action) });
          if (!res.ok) return { error: (await res.json()).message };
        }}
      />
    </EngineCardGrid>
  );
}
```

## Anatomy

```
EngineCard                    data-slot="engine-card"   data-engine, data-state
├─ header                     icon, title (h3), subtitle, state Badge (tone icon + words)
├─ body                       per engine: Meter, countdown, window, doses, counts, prediction, schedule
├─ error                      role="alert", the server's message as it is
└─ footer                     the log action and the details link
```

## API

| Prop | Type | Notes |
| --- | --- | --- |
| `snapshot` | `EngineSnapshot` | Required. Discriminated by `engine`. |
| `now` | `Date \| string \| number` | Fixed clock for countdowns. Omit to follow the clock. |
| `live` | `boolean` | Tick every second. Default `true`. |
| `onAction` | `(action: EngineAction) => Promise<void \| { error?: string }>` | Log unit, log wake, log dose, record dose. The error is shown as is. |
| `detailHref` | `string` | Link to the engine's page. |
| `headingAs` | `"h2" \| "h3" \| "h4"` | Default `"h3"`. |
| `loading` | `boolean` | Skeleton. |
| `hideTitle` | `boolean` | For pages that already name the engine. |
| `labels` | `Partial<EngineCardLabels>` | Override any string. |

Units come from `Measure` (millilitres, minutes, hours, days) in an LTR isolate, so they keep their order in Arabic.
The pure helpers (`summariseDays`, `bucketDays`, `engineTone`, `summariseMedication`, `splitDuration`) are exported too.

## Examples

### Caffeine while blocked

```tsx
<EngineCard snapshot={{ engine: "caffeine", state: "blocked", blockMinutes: 90, wakeAt: "2026-09-29T07:00:00Z", blockEndsAt: "2026-09-29T08:30:00Z", violationsToday: 0, cupsToday: 0 }} />
```

Check the exact snapshot shapes in `health-engines.ts`.

## Code

### React

```tsx
import { EngineCard, EngineCardGrid, type EngineSnapshot } from "@fadymondy/nasaq/web";

const hydration: EngineSnapshot = {
  engine: "hydration",
  state: "idle",
  totalMl: 1500,
  dailyCapMl: 5000,
  unitMl: 250,
  unitsLogged: 6,
  unitsTotal: 20,
};

export function Today() {
  return (
    <EngineCardGrid>
      <EngineCard
        snapshot={hydration}
        detailHref="/health/hydration"
        onAction={async (action) => {
          const res = await fetch("/api/engines/log", { method: "POST", body: JSON.stringify(action) });
          if (!res.ok) return { error: (await res.json()).message };
        }}
      />
    </EngineCardGrid>
  );
}
```

### shadcn

```tsx
import { EngineCard, EngineCardGrid } from "@/components/ui/engine-card";
import { type EngineSnapshot } from "@/components/ui/health-engines";

const hydration: EngineSnapshot = {
  engine: "hydration",
  state: "idle",
  totalMl: 1500,
  dailyCapMl: 5000,
  unitMl: 250,
  unitsLogged: 6,
  unitsTotal: 20,
};

export function Today() {
  return (
    <EngineCardGrid>
      <EngineCard
        snapshot={hydration}
        detailHref="/health/hydration"
        onAction={async (action) => {
          const res = await fetch("/api/engines/log", { method: "POST", body: JSON.stringify(action) });
          if (!res.ok) return { error: (await res.json()).message };
        }}
      />
    </EngineCardGrid>
  );
}
```

### Vue

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

const hydration = { engine: "hydration", state: "idle", totalMl: 750, dailyCapMl: 5000, unitMl: 250, unitsLogged: 3, unitsTotal: 20 } as const;
const caffeine = { engine: "caffeine", state: "awaiting_wake", blockMinutes: 90, violationsToday: 0, cupsToday: 0 } as const;
const triggers = { engine: "triggers", triggerBearing: 1, safe: 3, unclassified: 0, families: [{ id: "gout", count: 1 }] } as const;

// Resolve with nothing on success, or { error } to show the server message.
async function onAction() {
  await new Promise((resolve) => setTimeout(resolve, 400));
}
</script>

<template>
  <NqEngineCardGrid>
    <NqEngineCard :snapshot="hydration" :on-action="onAction" detail-href="/engines/hydration" />
    <NqEngineCard :snapshot="caffeine" :on-action="onAction" />
    <NqEngineCard :snapshot="triggers" />
  </NqEngineCardGrid>
</template>
```

### Blade

```blade
<x-nq::engine-card.grid>
    <x-nq::engine-card
        :snapshot="['engine' => 'hydration', 'state' => 'cooldown', 'totalMl' => 750, 'dailyCapMl' => 5000, 'unitMl' => 250, 'unitsLogged' => 3, 'unitsTotal' => 20, 'nextAllowedAt' => '2026-09-29T10:00:30Z']"
        now="2026-09-29T10:00:00Z"
        actions
        detail-href="/engines/hydration"
    />
    <x-nq::engine-card :snapshot="['engine' => 'caffeine', 'state' => 'awaiting_wake', 'blockMinutes' => 90, 'violationsToday' => 0, 'cupsToday' => 0]" actions />
    <x-nq::engine-card
        :snapshot="['engine' => 'medication', 'graceMinutes' => 60, 'doses' => [
            ['id' => 'a', 'name' => 'Morning', 'scheduledFor' => '2026-09-29T08:00:00Z', 'status' => 'logged'],
            ['id' => 'b', 'name' => 'Noon', 'scheduledFor' => '2026-09-29T09:30:00Z', 'status' => 'grace_open'],
        ]]"
        actions
    />
    <x-nq::engine-card :snapshot="['engine' => 'triggers', 'triggerBearing' => 1, 'safe' => 3, 'unclassified' => 0, 'families' => [['id' => 'gout', 'count' => 1]]]" />
</x-nq::engine-card.grid>
```

### HTML + Alpine

```html
<div data-slot="engine-card-grid" class="grid grid-cols-[repeat(auto-fill,minmax(min(100%,20rem),1fr))] gap-4"><div data-slot="engine-card" data-engine="hydration" data-state="cooldown" data-tone="info"
     aria-labelledby="nq-engine-hydration-title"      data-error-text="Something went wrong. Try again." x-data="nqEngineCard"      class="flex flex-col gap-4 rounded-card border border-border bg-card py-4 text-card-foreground min-w-0">
            <div data-slot="card-header" class="grid auto-rows-min items-start gap-1 px-4 has-data-[slot=card-action]:grid-cols-[1fr_auto]"><div class="flex min-w-0 items-start gap-3">
                    <span aria-hidden="true" data-slot="engine-card-icon" class="grid size-9 shrink-0 place-items-center rounded-control bg-secondary text-muted-foreground [&_svg]:size-4.5">
                        <svg 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="M7 16.3c2.2 0 4-1.83 4-4.05 0-1.16-.57-2.26-1.71-3.19S7.29 6.75 7 5.3c-.29 1.45-1.14 2.84-2.29 3.76S3 11.1 3 12.25c0 2.22 1.8 4.05 4 4.05z"/>
  <path d="M12.56 6.6A10.97 10.97 0 0 0 14 3.02c.5 2.5 2 4.9 4 6.5s3 3.5 3 5.5a6.98 6.98 0 0 1-11.91 4.97"/>
</svg>                    </span>
                    <div class="flex min-w-0 flex-col gap-0.5">
                        <h3 data-slot="card-title" id="nq-engine-hydration-title" class="text-h3 text-foreground">Hydration</h3>
                        <div data-slot="card-description" class="text-pretty text-body-sm">One fixed unit at a time, up to a daily cap.</div>
                    </div>
                </div>
                        <div data-slot="card-action" class="col-start-2 row-span-2 row-start-1 self-start justify-self-end"><span data-slot="engine-card-state" title="State" class="inline-flex h-5 shrink-0 items-center gap-1 whitespace-nowrap rounded-[4px] border px-1.5 text-caption font-medium [&amp;_svg]:size-3 border-nq-info/40 bg-nq-info-soft text-nq-info-text">
                    <svg aria-hidden="true" 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"/>
  <circle cx="12" cy="12" r="1"/>
</svg>                    Cooling down
                </span></div></div>
        <div data-slot="card-content" class="px-4 flex flex-col gap-4"><div class="flex flex-col gap-3">
                    <div class="flex flex-wrap items-baseline gap-x-2 gap-y-1">
                        <span data-slot="engine-card-value" class="text-h2 leading-tight text-foreground"><bdi data-slot="measure" data-numeric="" dir="ltr" class="tabular-nums [unicode-bidi:isolate]">750 mL</bdi></span>
                        <span class="text-body-sm text-muted-foreground">of <bdi data-slot="measure" data-numeric="" dir="ltr" class="tabular-nums [unicode-bidi:isolate]">5,000 mL</bdi></span>
                    </div>
                    <div data-slot="meter" data-tone="default" role="meter"  aria-labelledby="nq-meter-08894704-label"     aria-valuemin="0" aria-valuemax="20" aria-valuenow="3" aria-valuetext="3%"
    class="flex w-full flex-col gap-1.5">
            <div data-slot="progress-head" class="flex items-baseline justify-between gap-3 text-body-sm">
            <span id="nq-meter-08894704-label" class="text-label text-foreground">Units today</span>            <span aria-hidden="true" class="text-muted-foreground tabular-nums">⁦3 cups⁩ / ⁦20 cups⁩</span>        </div>
        <div data-slot="meter-track" class="relative block w-full overflow-hidden rounded-full bg-nq-surface-soft h-2">
        <div data-slot="meter-indicator" style="inset-inline-start:0;width:15%" class="block h-full rounded-full transition-[width] duration-300 ease-nq motion-reduce:transition-none bg-primary"></div>
    </div>
</div>
                    <ol aria-hidden="true" data-slot="engine-card-units" class="m-0 flex list-none flex-wrap gap-1 p-0">
                                                    <li class="size-3.5 rounded-full border border-primary bg-primary"></li>
                                                    <li class="size-3.5 rounded-full border border-primary bg-primary"></li>
                                                    <li class="size-3.5 rounded-full border border-primary bg-primary"></li>
                                                    <li class="size-3.5 rounded-full border border-border bg-transparent"></li>
                                                    <li class="size-3.5 rounded-full border border-border bg-transparent"></li>
                                                    <li class="size-3.5 rounded-full border border-border bg-transparent"></li>
                                                    <li class="size-3.5 rounded-full border border-border bg-transparent"></li>
                                                    <li class="size-3.5 rounded-full border border-border bg-transparent"></li>
                                                    <li class="size-3.5 rounded-full border border-border bg-transparent"></li>
                                                    <li class="size-3.5 rounded-full border border-border bg-transparent"></li>
                                                    <li class="size-3.5 rounded-full border border-border bg-transparent"></li>
                                                    <li class="size-3.5 rounded-full border border-border bg-transparent"></li>
                                                    <li class="size-3.5 rounded-full border border-border bg-transparent"></li>
                                                    <li class="size-3.5 rounded-full border border-border bg-transparent"></li>
                                                    <li class="size-3.5 rounded-full border border-border bg-transparent"></li>
                                                    <li class="size-3.5 rounded-full border border-border bg-transparent"></li>
                                                    <li class="size-3.5 rounded-full border border-border bg-transparent"></li>
                                                    <li class="size-3.5 rounded-full border border-border bg-transparent"></li>
                                                    <li class="size-3.5 rounded-full border border-border bg-transparent"></li>
                                                    <li class="size-3.5 rounded-full border border-border bg-transparent"></li>
                                            </ol>
                </div>
                                        <p role="alert" data-slot="engine-card-error" hidden x-show="error" x-text="error" class="flex items-start gap-2 rounded-control border border-nq-warning/30 bg-nq-warning-soft px-3 py-2 text-body-sm text-foreground"></p></div>
                    <div data-slot="card-footer" class="flex flex-wrap items-center gap-2 px-4"><button data-slot="button"
     type="button"                  disabled      data-disabled     x-on:click="act(&#039;log_unit&#039;)" x-bind:disabled="busy || true" x-bind:data-disabled="(busy || true) ? &#039;&#039; : null" x-bind:aria-busy="pending === &#039;log_unit:&#039; ? &#039;true&#039; : null" class="inline-flex shrink-0 select-none items-center justify-center gap-2 whitespace-nowrap rounded-control border border-transparent font-sans text-label transition-colors duration-150 ease-nq min-h-[var(--nq-touch-min,0px)] outline-none focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-nq-focus disabled:pointer-events-none disabled:opacity-50 data-disabled:pointer-events-none data-disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0 bg-primary text-primary-foreground hover:bg-[color-mix(in_oklab,var(--nq-action)_88%,var(--nq-fg))] h-control-sm px-2.5">
        Wait ⁦30 sec⁩</button>
                                                    <a data-slot="engine-card-details" href="/engines/hydration" aria-describedby="nq-engine-hydration-title" class="inline-flex shrink-0 select-none items-center justify-center gap-2 whitespace-nowrap rounded-control border border-transparent font-sans text-label transition-colors duration-150 ease-nq min-h-[var(--nq-touch-min,0px)] outline-none focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-nq-focus disabled:pointer-events-none disabled:opacity-50 data-disabled:pointer-events-none data-disabled:opacity-50 [&amp;_svg]:pointer-events-none [&amp;_svg]:size-4 [&amp;_svg]:shrink-0 text-foreground hover:bg-nq-hover h-control-sm px-2.5 ms-auto">
                        Details
                        <svg aria-hidden="true" class="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="m9 18 6-6-6-6"/>
</svg>                    </a></div>
            </div>
    <div data-slot="engine-card" data-engine="caffeine" data-state="awaiting_wake" data-tone="neutral"
     aria-labelledby="nq-engine-caffeine-title"      data-error-text="Something went wrong. Try again." x-data="nqEngineCard"      class="flex flex-col gap-4 rounded-card border border-border bg-card py-4 text-card-foreground min-w-0">
            <div data-slot="card-header" class="grid auto-rows-min items-start gap-1 px-4 has-data-[slot=card-action]:grid-cols-[1fr_auto]"><div class="flex min-w-0 items-start gap-3">
                    <span aria-hidden="true" data-slot="engine-card-icon" class="grid size-9 shrink-0 place-items-center rounded-control bg-secondary text-muted-foreground [&_svg]:size-4.5">
                        <svg 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="M10 2v2"/>
  <path d="M14 2v2"/>
  <path d="M16 8a1 1 0 0 1 1 1v8a4 4 0 0 1-4 4H7a4 4 0 0 1-4-4V9a1 1 0 0 1 1-1h14a4 4 0 1 1 0 8h-1"/>
  <path d="M6 2v2"/>
</svg>                    </span>
                    <div class="flex min-w-0 flex-col gap-0.5">
                        <h3 data-slot="card-title" id="nq-engine-caffeine-title" class="text-h3 text-foreground">Caffeine Block</h3>
                        <div data-slot="card-description" class="text-pretty text-body-sm">No caffeine for a set time after waking.</div>
                    </div>
                </div>
                        <div data-slot="card-action" class="col-start-2 row-span-2 row-start-1 self-start justify-self-end"><span data-slot="engine-card-state" title="State" class="inline-flex h-5 shrink-0 items-center gap-1 whitespace-nowrap rounded-[4px] border px-1.5 text-caption font-medium [&amp;_svg]:size-3 border-border bg-secondary text-foreground">
                    <svg aria-hidden="true" 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="M8 12h8"/>
</svg>                    Waiting for wake time
                </span></div></div>
        <div data-slot="card-content" class="px-4 flex flex-col gap-4"><div class="flex flex-col gap-3">
                                            <p class="text-body-sm text-muted-foreground">Log when you woke up to start the block.</p>
                                        <dl class="m-0 grid grid-cols-2 gap-x-4 gap-y-3">
                        <div data-slot="engine-card-fact" class="flex min-w-0 flex-col gap-0.5">
                            <dt class="text-caption text-muted-foreground">Caffeine drinks today</dt>
                            <dd class="m-0 text-body-sm font-medium text-foreground">
                                                                    <bdi data-slot="measure" data-numeric="" dir="ltr" class="tabular-nums [unicode-bidi:isolate]">0 cups</bdi>
                                                            </dd>
                        </div>
                        <div data-slot="engine-card-fact" class="flex min-w-0 flex-col gap-0.5">
                            <dt class="text-caption text-muted-foreground">Logged inside the block</dt>
                            <dd class="m-0 text-body-sm font-medium text-foreground"><bdi data-slot="measure" data-numeric="" dir="ltr" class="tabular-nums [unicode-bidi:isolate]">0</bdi></dd>
                        </div>
                    </dl>
                </div>
                                        <p role="alert" data-slot="engine-card-error" hidden x-show="error" x-text="error" class="flex items-start gap-2 rounded-control border border-nq-warning/30 bg-nq-warning-soft px-3 py-2 text-body-sm text-foreground"></p></div>
                    <div data-slot="card-footer" class="flex flex-wrap items-center gap-2 px-4"><button data-slot="button"
     type="button"                         x-on:click="act(&#039;log_wake&#039;)" x-bind:disabled="busy" x-bind:data-disabled="busy ? &#039;&#039; : null" x-bind:aria-busy="pending === &#039;log_wake:&#039; ? &#039;true&#039; : null" class="inline-flex shrink-0 select-none items-center justify-center gap-2 whitespace-nowrap rounded-control border border-transparent font-sans text-label transition-colors duration-150 ease-nq min-h-[var(--nq-touch-min,0px)] outline-none focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-nq-focus disabled:pointer-events-none disabled:opacity-50 data-disabled:pointer-events-none data-disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0 bg-primary text-primary-foreground hover:bg-[color-mix(in_oklab,var(--nq-action)_88%,var(--nq-fg))] h-control-sm px-2.5">
        I woke up</button></div>
            </div>
    <div data-slot="engine-card" data-engine="medication" data-state="grace_open" data-tone="info"
     aria-labelledby="nq-engine-medication-title"      data-error-text="Something went wrong. Try again." x-data="nqEngineCard"      class="flex flex-col gap-4 rounded-card border border-border bg-card py-4 text-card-foreground min-w-0">
            <div data-slot="card-header" class="grid auto-rows-min items-start gap-1 px-4 has-data-[slot=card-action]:grid-cols-[1fr_auto]"><div class="flex min-w-0 items-start gap-3">
                    <span aria-hidden="true" data-slot="engine-card-icon" class="grid size-9 shrink-0 place-items-center rounded-control bg-secondary text-muted-foreground [&_svg]:size-4.5">
                        <svg 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="m10.5 20.5 10-10a4.95 4.95 0 1 0-7-7l-10 10a4.95 4.95 0 1 0 7 7Z"/>
  <path d="m8.5 8.5 7 7"/>
</svg>                    </span>
                    <div class="flex min-w-0 flex-col gap-0.5">
                        <h3 data-slot="card-title" id="nq-engine-medication-title" class="text-h3 text-foreground">Medication Grace</h3>
                        <div data-slot="card-description" class="text-pretty text-body-sm">Was each scheduled dose logged, and on time?</div>
                    </div>
                </div>
                        <div data-slot="card-action" class="col-start-2 row-span-2 row-start-1 self-start justify-self-end"><span data-slot="engine-card-state" title="State" class="inline-flex h-5 shrink-0 items-center gap-1 whitespace-nowrap rounded-[4px] border px-1.5 text-caption font-medium [&amp;_svg]:size-3 border-nq-info/40 bg-nq-info-soft text-nq-info-text">
                    <svg aria-hidden="true" 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"/>
  <circle cx="12" cy="12" r="1"/>
</svg>                    Dose window open
                </span></div></div>
        <div data-slot="card-content" class="px-4 flex flex-col gap-4"><div class="flex flex-col gap-3">
                        <div class="flex flex-wrap items-baseline gap-x-2">
                            <span data-slot="engine-card-value" class="text-h2 leading-tight text-foreground"><bdi data-slot="measure" data-numeric="" dir="ltr" class="tabular-nums [unicode-bidi:isolate]">1</bdi></span>
                            <span class="text-body-sm text-muted-foreground">of <bdi data-slot="measure" data-numeric="" dir="ltr" class="tabular-nums [unicode-bidi:isolate]">2</bdi> · Logged</span>
                        </div>
                        <ul class="m-0 flex list-none flex-col divide-y divide-border p-0" data-slot="engine-card-doses">
                                                            <li class="flex items-center justify-between gap-3 py-2 first:pt-0 last:pb-0">
                                    <div class="flex min-w-0 flex-col">
                                        <span class="truncate text-body-sm font-medium text-foreground">Morning</span>
                                        <span class="text-caption text-muted-foreground"><bdi dir="ltr" class="tabular-nums">8:00 AM</bdi></span>
                                    </div>
                                    <div class="flex shrink-0 items-center 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">
            <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="Logged" >Logged</span>
</span>
                                                                            </div>
                                </li>
                                                            <li class="flex items-center justify-between gap-3 py-2 first:pt-0 last:pb-0">
                                    <div class="flex min-w-0 flex-col">
                                        <span class="truncate text-body-sm font-medium text-foreground">Noon</span>
                                        <span class="text-caption text-muted-foreground"><bdi dir="ltr" class="tabular-nums">9:30 AM</bdi></span>
                                    </div>
                                    <div class="flex shrink-0 items-center gap-2">
                                        <span data-slot="status" data-tone="info" class="inline-flex min-w-0 items-center gap-1.5 text-body-sm text-foreground">
            <svg aria-hidden="true" class="size-3.5 shrink-0 text-nq-info-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">
  <line x1="10" x2="14" y1="2" y2="2"/>
  <line x1="12" x2="15" y1="14" y2="11"/>
  <circle cx="12" cy="14" r="8"/>
</svg>        <span class="truncate"  title="Window open" >Window open</span>
</span>
                                                                                    <button data-slot="button"
     type="button"                         x-on:click="act(&#039;log_dose&#039;, &#039;b&#039;)" x-bind:disabled="busy" x-bind:data-disabled="busy ? &#039;&#039; : null" x-bind:aria-busy="pending === &#039;log_dose:b&#039; ? &#039;true&#039; : null" class="inline-flex shrink-0 select-none items-center justify-center gap-2 whitespace-nowrap rounded-control border font-sans text-label transition-colors duration-150 ease-nq min-h-[var(--nq-touch-min,0px)] outline-none focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-nq-focus disabled:pointer-events-none disabled:opacity-50 data-disabled:pointer-events-none data-disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0 border-border bg-card text-foreground hover:bg-nq-hover h-control-sm px-2.5">
        Log dose</button>
                                                                            </div>
                                </li>
                                                    </ul>
                        <p class="text-caption text-muted-foreground">Each dose can be logged on time for ⁦1 hr⁩ after its scheduled time.</p>
                        <p class="text-caption text-muted-foreground">Consult your doctor.</p>
                    </div>
                                                        <p role="alert" data-slot="engine-card-error" hidden x-show="error" x-text="error" class="flex items-start gap-2 rounded-control border border-nq-warning/30 bg-nq-warning-soft px-3 py-2 text-body-sm text-foreground"></p></div>
                    <div data-slot="card-footer" class="flex flex-wrap items-center gap-2 px-4"></div>
            </div>
    <div data-slot="engine-card" data-engine="triggers" data-state="exposed" data-tone="warning"
     aria-labelledby="nq-engine-triggers-title"          class="flex flex-col gap-4 rounded-card border border-border bg-card py-4 text-card-foreground min-w-0">
            <div data-slot="card-header" class="grid auto-rows-min items-start gap-1 px-4 has-data-[slot=card-action]:grid-cols-[1fr_auto]"><div class="flex min-w-0 items-start gap-3">
                    <span aria-hidden="true" data-slot="engine-card-icon" class="grid size-9 shrink-0 place-items-center rounded-control bg-secondary text-muted-foreground [&_svg]:size-4.5">
                        <svg 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="M3 2v7c0 1.1.9 2 2 2h4a2 2 0 0 0 2-2V2"/>
  <path d="M7 2v20"/>
  <path d="M21 15V2a5 5 0 0 0-5 5v6c0 1.1.9 2 2 2h3Zm0 0v7"/>
</svg>                    </span>
                    <div class="flex min-w-0 flex-col gap-0.5">
                        <h3 data-slot="card-title" id="nq-engine-triggers-title" class="text-h3 text-foreground">Trigger Families</h3>
                        <div data-slot="card-description" class="text-pretty text-body-sm">What was logged, by trigger family.</div>
                    </div>
                </div>
                        <div data-slot="card-action" class="col-start-2 row-span-2 row-start-1 self-start justify-self-end"><span data-slot="engine-card-state" title="State" class="inline-flex h-5 shrink-0 items-center gap-1 whitespace-nowrap rounded-[4px] border px-1.5 text-caption font-medium [&amp;_svg]:size-3 border-nq-warning/40 bg-nq-warning-soft text-nq-warning-text">
                    <svg aria-hidden="true" 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>                    Trigger logged
                </span></div></div>
        <div data-slot="card-content" class="px-4 flex flex-col gap-4"><div class="flex flex-col gap-3">
                    <dl class="m-0 grid grid-cols-2 gap-x-4 gap-y-3">
                                                    <div data-slot="engine-card-fact" class="flex min-w-0 flex-col gap-0.5">
                                <dt class="text-caption text-muted-foreground">Trigger-bearing</dt>
                                <dd class="m-0 text-body-sm font-medium text-foreground"><span class="text-h3"><bdi data-slot="measure" data-numeric="" dir="ltr" class="tabular-nums [unicode-bidi:isolate]">1</bdi></span></dd>
                            </div>
                                                    <div data-slot="engine-card-fact" class="flex min-w-0 flex-col gap-0.5">
                                <dt class="text-caption text-muted-foreground">Judged safe</dt>
                                <dd class="m-0 text-body-sm font-medium text-foreground"><span class="text-h3"><bdi data-slot="measure" data-numeric="" dir="ltr" class="tabular-nums [unicode-bidi:isolate]">3</bdi></span></dd>
                            </div>
                                                    <div data-slot="engine-card-fact" class="flex min-w-0 flex-col gap-0.5">
                                <dt class="text-caption text-muted-foreground">Not judged</dt>
                                <dd class="m-0 text-body-sm font-medium text-foreground"><span class="text-h3"><bdi data-slot="measure" data-numeric="" dir="ltr" class="tabular-nums [unicode-bidi:isolate]">0</bdi></span></dd>
                            </div>
                                            </dl>
                                            <div class="flex flex-col gap-1.5">
                            <span class="text-caption text-muted-foreground">By family</span>
                            <ul class="m-0 flex list-none flex-wrap gap-1.5 p-0">
                                                                    <li><span data-slot="badge"     class="inline-flex h-5 shrink-0 items-center gap-1 whitespace-nowrap rounded-[4px] border px-1.5 text-caption font-medium [&_svg]:size-3 border-border text-muted-foreground">Gout <bdi data-slot="measure" data-numeric="" dir="ltr" class="tabular-nums [unicode-bidi:isolate]">1</bdi></span>
</li>
                                                            </ul>
                        </div>
                                                        </div></div>
            </div></div>
```
