# ApiKeys

> API key management with a create form (name, scopes, expiry), a one-time secret reveal with copy, a masked list with scopes and last used, and confirmed rotate and revoke, driven by async callbacks.

Source: https://docs.nasaqui.com/components/api-keys

## Install

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

Create, see and retire API keys. The secret is shown once, in a dialog with a copy button, and never
again: the list only has the public prefix and the last four characters. It has no backend: your
callbacks call your server and you pass the updated `keys` back.

## When to use

- A developer or settings page where people make keys for scripts and servers.
- Any place a secret must be shown exactly once.

## When not to use

- Session or OAuth tokens: those are not managed by hand.
- Showing a secret you keep readable: this component assumes you cannot show it again.

## Import

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

## Quick start

```tsx
import { ApiKeys, type ApiKeyRecord } from "@fadymondy/nasaq/web";

declare const keys: ApiKeyRecord[];
declare const api: {
  create(input: { name: string; scopes: string[]; expiresInDays: number | null }): Promise<{ secret: string }>;
  revoke(id: string): Promise<void>;
};

export function Keys() {
  return (
    <ApiKeys
      keys={keys}
      scopes={[
        { id: "read", label: "Read" },
        { id: "write", label: "Write" },
      ]}
      onCreate={async (input) => ({ secret: (await api.create(input)).secret })}
      onRevoke={(id) => api.revoke(id)}
    />
  );
}
```

## Anatomy

```
ApiKeys                         data-slot="api-keys" (Card)
├─ header + Create key          opens the create Dialog: name, scope checkboxes, expiry Select
├─ list                         data-slot="api-key" (data-status="active|expiring|expired|revoked")
│  ├─ name, masked key          nsq_live_a1b2••••9f3c (dir="ltr")
│  ├─ scope badges, status      Status: Active, Expires soon, Expired, Revoked
│  ├─ created, last used, expires
│  └─ Rotate and Revoke         each a ConfirmButton (AlertDialog)
└─ reveal dialog                data-slot="api-key-secret": Alert "copy it now" + CopyField
```

## API

**ApiKeys**: every `div` prop except `children`, plus:

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `keys` | `readonly ApiKeyRecord[]` | required | `{ id, name, prefix, last4?, scopes, createdAt, expiresAt?, lastUsedAt?, revokedAt? }`. Dates are ms, ISO string or Date. |
| `scopes` | `readonly ApiKeyScope[]` | required | Every scope a key can get: `{ id, label, description? }`. |
| `defaultScopes` | `readonly string[]` | none | Ticked when the form opens. |
| `expiryOptions` | `readonly (number \| null)[]` | 7, 30, 90, 365, never | Days, `null` is never. |
| `defaultExpiryDays` | `number \| null` | `90` | Preselected expiry. |
| `onCreate` | `(input) => Promise<{ secret } \| { error }>` | required | Make the key. The secret is shown once. |
| `onRotate` | `(id) => Promise<{ secret } \| { error }>` | | Shows Rotate. The new secret is revealed once. |
| `onRevoke` | `(id) => Promise<void \| { error? }>` | | Shows Revoke. |
| `labels` | `Partial<ApiKeysLabels>` | | Override any string. |

**Helpers** (pure, tested): `maskKey(prefix, last4)`, `keyStatus(record, now?)`, `expiryFromDays(days, now?)`,
`daysLeft(date, now?)`, `toggleScope(all, selected, id)`, `EXPIRING_DAYS` (7).

## Examples

**Rotate**

```tsx
import { ApiKeys, type ApiKeyRecord } from "@fadymondy/nasaq/web";

declare const keys: ApiKeyRecord[];
declare const api: { rotate(id: string): Promise<string> };

export const Rotating = () => (
  <ApiKeys
    keys={keys}
    scopes={[{ id: "read", label: "Read" }]}
    onCreate={async () => ({ error: "Not in this example" })}
    onRotate={async (id) => ({ secret: await api.rotate(id) })}
  />
);
```

## Accessibility

- Dialogs trap focus and return it. The confirm dialogs are `AlertDialog`: focus lands on Cancel, Escape closes.
- Status is text plus colour, never colour alone. Scope checkboxes are in a labelled group.
- The reveal dialog announces that the secret will not be shown again. Errors are `role="alert"`.

## RTL & i18n

- English and Arabic strings follow the Nasaq locale. Keys, prefixes and secrets are `dir="ltr"`.

## Styling & tokens

- Built on `Card`, `Dialog`, `AlertDialog`, `Status`, `Badge`, `CopyField` and `--nq-*` tokens.
- Target `[data-slot="api-key"][data-status="expiring"]`.

## Do / Don't

- Do store only a hash of the secret on the server and return the secret from `onCreate` once.
- Do give every key the narrowest scopes and an expiry.
- Don't log the returned secret or keep it in client state after the dialog closes. The component drops it after close.
- Don't show the full key in the list.

## Related

- [`McpConnect`](https://docs.nasaqui.com/components/mcp-connect)
- [`CopyButton`](https://docs.nasaqui.com/components/copy-button)
- [`AlertDialog`](https://docs.nasaqui.com/components/alert-dialog)

## Lab

https://docs.nasaqui.com/?path=/docs/components-developer-tools-api-keys--docs

## Code

### React

```tsx
import { ApiKeys, type ApiKeyRecord } from "@fadymondy/nasaq/web";

declare const keys: ApiKeyRecord[];
declare const api: {
  create(input: { name: string; scopes: string[]; expiresInDays: number | null }): Promise<{ secret: string }>;
  revoke(id: string): Promise<void>;
};

export function Keys() {
  return (
    <ApiKeys
      keys={keys}
      scopes={[
        { id: "read", label: "Read" },
        { id: "write", label: "Write" },
      ]}
      onCreate={async (input) => ({ secret: (await api.create(input)).secret })}
      onRevoke={(id) => api.revoke(id)}
    />
  );
}
```

### shadcn

```tsx
import { ApiKeys, type ApiKeyRecord } from "@/components/ui/api-keys";

declare const keys: ApiKeyRecord[];
declare const api: {
  create(input: { name: string; scopes: string[]; expiresInDays: number | null }): Promise<{ secret: string }>;
  revoke(id: string): Promise<void>;
};

export function Keys() {
  return (
    <ApiKeys
      keys={keys}
      scopes={[
        { id: "read", label: "Read" },
        { id: "write", label: "Write" },
      ]}
      onCreate={async (input) => ({ secret: (await api.create(input)).secret })}
      onRevoke={(id) => api.revoke(id)}
    />
  );
}
```

### Vue

```vue
<script setup lang="ts">
import { NqApiKeys, type ApiKeyRecord } from "@fadymondy/nasaq/vue";
import { ref } from "vue";

const day = 86_400_000;
const keys = ref<ApiKeyRecord[]>([
  { id: "k1", name: "Production server", prefix: "nsq_live_a1b2", last4: "wxyz", scopes: ["read", "write"], createdAt: Date.now() - 40 * day, lastUsedAt: Date.now() - 3 * 3_600_000, expiresAt: Date.now() + 200 * day },
  { id: "k2", name: "CI pipeline", prefix: "nsq_live_c3d4", last4: "q9rs", scopes: ["read"], createdAt: Date.now() - 90 * day, lastUsedAt: null, expiresAt: Date.now() + 4 * day },
]);

const scopes = [
  { id: "read", label: "Read", description: "List and fetch records" },
  { id: "write", label: "Write", description: "Create and change records" },
];

async function onCreate(input: { name: string; scopes: string[]; expiresInDays: number | null }) {
  const id = `k${keys.value.length + 1}`;
  keys.value = [
    ...keys.value,
    {
      id,
      name: input.name,
      prefix: `nsq_live_${id}`,
      last4: "0000",
      scopes: input.scopes,
      createdAt: Date.now(),
      expiresAt: input.expiresInDays == null ? null : Date.now() + input.expiresInDays * day,
    },
  ];
  return { secret: `nsq_live_${id}_s3cr3t0000` };
}

async function onRevoke(id: string) {
  keys.value = keys.value.map((k) => (k.id === id ? { ...k, revokedAt: Date.now() } : k));
}
</script>

<template>
  <NqApiKeys :keys="keys" :scopes="scopes" :on-create="onCreate" :on-revoke="onRevoke" />
</template>
```

### Blade

```blade
@php
    $keys = [
        ['id' => 'k1', 'name' => 'Production server', 'prefix' => 'nsq_live_a1b2', 'last4' => 'wxyz', 'scopes' => ['read', 'write'], 'createdAt' => '2025-01-10T09:00:00Z', 'lastUsedAt' => '2025-03-01T08:00:00Z', 'expiresAt' => '2099-01-01T00:00:00Z'],
        ['id' => 'k2', 'name' => 'CI pipeline', 'prefix' => 'nsq_live_c3d4', 'last4' => 'q9rs', 'scopes' => ['read'], 'createdAt' => '2025-01-20T09:00:00Z', 'lastUsedAt' => null, 'expiresAt' => null, 'revokedAt' => '2025-02-01T00:00:00Z'],
    ];
    $scopes = [
        ['id' => 'read', 'label' => 'Read', 'description' => 'List and fetch records'],
        ['id' => 'write', 'label' => 'Write', 'description' => 'Create and change records'],
    ];
@endphp
<x-nq::api-keys :keys="$keys" :scopes="$scopes" />
```

### HTML + Alpine

```html
<div data-slot="api-keys" x-data="nqApiKeys(JSON.parse('{\u0022scopes\u0022:[\u0022read\u0022,\u0022write\u0022],\u0022defaultScopes\u0022:[],\u0022expiry\u0022:\u002290\u0022,\u0022names\u0022:{\u0022k1\u0022:\u0022Production server\u0022,\u0022k2\u0022:\u0022CI pipeline\u0022},\u0022labels\u0022:{\u0022revealTitle\u0022:\u0022Copy your new key now\u0022,\u0022revealRotated\u0022:\u0022New key for {name}\u0022,\u0022genericError\u0022:\u0022Something went wrong. Try again.\u0022}}'))" class="flex flex-col gap-4 rounded-card border border-border bg-card py-4 text-card-foreground w-full max-w-4xl">
    <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] sm:flex sm:items-start sm:justify-between sm:gap-4"><div class="flex flex-col gap-1.5">
            <h2 data-slot="card-title" class="text-label text-foreground">API keys</h2>
            <div data-slot="card-description" class="text-body-sm text-muted-foreground">Keys let your own code call the API. Give each key only the access it needs.</div>
        </div>
        <button data-slot="button"
     type="button"                         x-on:click="openCreate()" 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 px-[var(--nq-control-pad)] mt-3 sm:mt-0">
        <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">
  <path d="M5 12h14"/>
  <path d="M12 5v14"/>
</svg>            Create key</button></div>
    <div data-slot="card-content" class="px-4 flex flex-col gap-3"><template x-if="pageError">
            <div data-slot="alert" data-tone="danger" role="alert"
     x-data="nqAlert()" x-modelable="open" x-show="open"     x-on:nq:dismiss="pageError = null" class="relative grid grid-cols-[auto_1fr_auto] items-start gap-x-3 rounded-card border p-3 text-start border-nq-danger/30 bg-nq-danger-soft">
    <svg aria-hidden="true" data-slot="alert-icon" class="mt-0.5 size-4 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>    <div data-slot="alert-body" class="flex min-w-0 flex-col gap-0.5">
                            <div data-slot="alert-description" class="text-body-sm text-foreground"><span x-text="pageError"></span></div>
            </div>
            <div data-slot="alert-actions" class="ms-3 flex items-center gap-1">
                            <button data-slot="button"
     type="button"                         aria-label="Dismiss" x-on:click="dismiss()" 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]:shrink-0 hover:bg-nq-hover size-control-sm p-0 text-muted-foreground [&_svg]:size-3.5">
        <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">
  <path d="M18 6 6 18"/>
  <path d="m6 6 12 12"/>
</svg></button>
                    </div>
    </div>
        </template>
                    <ul aria-label="API keys" class="overflow-hidden rounded-card border border-border">
                                                        <li data-slot="api-key" data-status="active" class="flex flex-col gap-3 border-t border-border px-4 py-3 first:border-t-0 sm:flex-row sm:items-start sm:justify-between">
                        <div class="flex min-w-0 flex-col gap-2">
                            <div class="flex flex-wrap items-center gap-x-3 gap-y-1">
                                <span dir="auto" class="text-label text-foreground">Production server</span>
                                <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="Active" >Active</span>
</span>
                            </div>
                            <code dir="ltr" data-slot="api-key-masked" class="w-fit max-w-full truncate text-start font-mono text-code text-muted-foreground">nsq_live_a1b2••••••••wxyz</code>
                            <ul aria-label="Scopes" class="flex flex-wrap gap-1">
                                                                    <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">Read</span>
</li>
                                                                    <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">Write</span>
</li>
                                                            </ul>
                            <dl class="flex flex-wrap gap-x-5 gap-y-1 text-caption text-muted-foreground">
                                <div class="flex gap-1">
                                    <dt>Created</dt>
                                    <dd><time data-slot="date-time" datetime="2025-01-10T09:00:00+00:00" dir="auto"     class="tabular-nums [unicode-bidi:isolate]">Jan 10, 2025</time>
</dd>
                                </div>
                                <div class="flex gap-1">
                                    <dt>Last used</dt>
                                    <dd><time data-slot="date-time" datetime="2025-03-01T08:00:00+00:00" dir="auto"  title="Mar 1, 2025"     class="tabular-nums [unicode-bidi:isolate]">1 year ago</time>
</dd>
                                </div>
                                <div class="flex gap-1">
                                    <dt>Expires</dt>
                                    <dd>
                                        <time data-slot="date-time" datetime="2099-01-01T00:00:00+00:00" dir="auto"     class="tabular-nums [unicode-bidi:isolate]">Jan 1, 2099</time>
                                    </dd>
                                </div>
                            </dl>
                        </div>
                                                    <div role="group" aria-label="Actions for Production server" class="flex shrink-0 flex-wrap gap-2">
                                                                    <div data-slot="alert-dialog" x-data="nqAlertDialog(false)" x-modelable="open" x-id="['nq-alert-dialog']" class="contents">
    <button data-slot="alert-dialog-trigger"
     type="button"                         aria-haspopup="dialog" x-on:click="show()" :aria-expanded="open" 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">
        <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">
  <path d="M3 12a9 9 0 0 1 9-9 9.75 9.75 0 0 1 6.74 2.74L21 8"/>
  <path d="M21 3v5h-5"/>
  <path d="M21 12a9 9 0 0 1-9 9 9.75 9.75 0 0 1-6.74-2.74L3 16"/>
  <path d="M8 16H3v5"/>
</svg>                                        Rotate</button>
    <template x-teleport="body">
    <div data-slot="alert-dialog-portal">
        <div data-slot="alert-dialog-backdrop" x-nq-presence="open" class="fixed inset-0 z-50 bg-nq-fg/15 dark:bg-nq-bg/60 transition-opacity duration-150 ease-nq data-starting-style:opacity-0 data-ending-style:opacity-0"></div>
        <div data-slot="alert-dialog-content" x-bind="popup" x-nq-presence="open" x-trap.noscroll="open"
            class="fixed inset-0 z-50 m-auto grid h-fit w-[calc(100%-2rem)] max-w-md gap-4 rounded-floating border border-border bg-popover p-6 text-popover-foreground outline-none max-h-[calc(100dvh-2rem)] overflow-y-auto transition-opacity duration-150 ease-nq data-starting-style:opacity-0 data-ending-style:opacity-0">
            <div data-slot="alert-dialog-header" class="flex flex-col gap-1.5 text-start"><h2 data-slot="alert-dialog-title" :id="$id('nq-alert-dialog', 'title')" class="text-h3 text-foreground">Rotate Production server?</h2>
                            <p data-slot="alert-dialog-description" :id="$id('nq-alert-dialog', 'description')" class="text-body-sm text-muted-foreground">A new secret replaces the old one, and the old one stops working at once. Update the places that use it.</p></div>
        <div data-slot="alert-dialog-footer" class="flex flex-col-reverse gap-2 sm:flex-row sm:justify-end"><button data-slot="alert-dialog-cancel"
     type="button"                         autofocus="autofocus" x-on:click="close()" 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 text-foreground hover:bg-nq-hover h-control px-[var(--nq-control-pad)]">
        Cancel</button>
            <button data-slot="alert-dialog-action"
     type="button"                         x-on:click.capture="close()" data-key-id="k1" x-on:click="rotate($el.dataset.keyId)" 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 px-[var(--nq-control-pad)]">
        Rotate key</button></div>
        </div>
    </div>
</template>
</div>
                                                                                                    <div data-slot="alert-dialog" x-data="nqAlertDialog(false)" x-modelable="open" x-id="['nq-alert-dialog']" class="contents">
    <button data-slot="alert-dialog-trigger"
     type="button"                         aria-haspopup="dialog" x-on:click="show()" :aria-expanded="open" 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-destructive text-destructive-foreground hover:bg-[color-mix(in_oklab,var(--nq-danger-solid)_88%,var(--nq-fg))] h-control-sm px-2.5">
        <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">
  <path d="M10 11v6"/>
  <path d="M14 11v6"/>
  <path d="M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6"/>
  <path d="M3 6h18"/>
  <path d="M8 6V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2"/>
</svg>                                        Revoke</button>
    <template x-teleport="body">
    <div data-slot="alert-dialog-portal">
        <div data-slot="alert-dialog-backdrop" x-nq-presence="open" class="fixed inset-0 z-50 bg-nq-fg/15 dark:bg-nq-bg/60 transition-opacity duration-150 ease-nq data-starting-style:opacity-0 data-ending-style:opacity-0"></div>
        <div data-slot="alert-dialog-content" x-bind="popup" x-nq-presence="open" x-trap.noscroll="open"
            class="fixed inset-0 z-50 m-auto grid h-fit w-[calc(100%-2rem)] max-w-md gap-4 rounded-floating border border-border bg-popover p-6 text-popover-foreground outline-none max-h-[calc(100dvh-2rem)] overflow-y-auto transition-opacity duration-150 ease-nq data-starting-style:opacity-0 data-ending-style:opacity-0">
            <div data-slot="alert-dialog-header" class="flex flex-col gap-1.5 text-start"><h2 data-slot="alert-dialog-title" :id="$id('nq-alert-dialog', 'title')" class="text-h3 text-foreground">Revoke Production server?</h2>
                            <p data-slot="alert-dialog-description" :id="$id('nq-alert-dialog', 'description')" class="text-body-sm text-muted-foreground">Anything using this key loses access immediately. This cannot be undone.</p></div>
        <div data-slot="alert-dialog-footer" class="flex flex-col-reverse gap-2 sm:flex-row sm:justify-end"><button data-slot="alert-dialog-cancel"
     type="button"                         autofocus="autofocus" x-on:click="close()" 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 text-foreground hover:bg-nq-hover h-control px-[var(--nq-control-pad)]">
        Cancel</button>
            <button data-slot="alert-dialog-action"
     type="button"                         x-on:click.capture="close()" data-key-id="k1" x-on:click="revoke($el.dataset.keyId)" 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-destructive text-destructive-foreground hover:bg-[color-mix(in_oklab,var(--nq-danger-solid)_88%,var(--nq-fg))] h-control px-[var(--nq-control-pad)]">
        Revoke key</button></div>
        </div>
    </div>
</template>
</div>
                                                            </div>
                                            </li>
                                                        <li data-slot="api-key" data-status="revoked" class="flex flex-col gap-3 border-t border-border px-4 py-3 first:border-t-0 sm:flex-row sm:items-start sm:justify-between">
                        <div class="flex min-w-0 flex-col gap-2">
                            <div class="flex flex-wrap items-center gap-x-3 gap-y-1">
                                <span dir="auto" class="text-label text-muted-foreground line-through decoration-1">CI pipeline</span>
                                <span data-slot="status" data-tone="neutral" 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-muted-foreground" 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"/>
</svg>        <span class="truncate"  title="Revoked" >Revoked</span>
</span>
                            </div>
                            <code dir="ltr" data-slot="api-key-masked" class="w-fit max-w-full truncate text-start font-mono text-code text-muted-foreground">nsq_live_c3d4••••••••q9rs</code>
                            <ul aria-label="Scopes" class="flex flex-wrap gap-1">
                                                                    <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">Read</span>
</li>
                                                            </ul>
                            <dl class="flex flex-wrap gap-x-5 gap-y-1 text-caption text-muted-foreground">
                                <div class="flex gap-1">
                                    <dt>Created</dt>
                                    <dd><time data-slot="date-time" datetime="2025-01-20T09:00:00+00:00" dir="auto"     class="tabular-nums [unicode-bidi:isolate]">Jan 20, 2025</time>
</dd>
                                </div>
                                <div class="flex gap-1">
                                    <dt>Last used</dt>
                                    <dd>Never used</dd>
                                </div>
                                <div class="flex gap-1">
                                    <dt>Expires</dt>
                                    <dd>
                                        Never expires
                                                                            </dd>
                                </div>
                            </dl>
                        </div>
                                                    <svg aria-hidden="true" class="hidden size-4 shrink-0 text-muted-foreground sm:block" 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="M20 13c0 5-3.5 7.5-7.66 8.95a1 1 0 0 1-.67-.01C7.5 20.5 4 18 4 13V6a1 1 0 0 1 1-1c2 0 4.5-1.2 6.24-2.72a1.17 1.17 0 0 1 1.52 0C14.51 3.81 17 5 19 5a1 1 0 0 1 1 1z"/>
  <path d="M12 8v4"/>
  <path d="M12 16h.01"/>
</svg>                                            </li>
                            </ul></div>
    <div data-slot="dialog" x-data="nqDialog(false)" x-modelable="open" x-id="['nq-dialog']" x-model="createOpen" class="contents">
    <template x-teleport="body">
    <div data-slot="dialog-portal">
        <div data-slot="dialog-backdrop" x-nq-presence="open" x-on:click="close()" class="fixed inset-0 z-50 bg-nq-fg/15 dark:bg-nq-bg/60 transition-opacity duration-150 ease-nq data-starting-style:opacity-0 data-ending-style:opacity-0"></div>
        <div data-slot="dialog-content" x-bind="popup" x-nq-presence="open" x-trap.noscroll="open"
            class="fixed inset-0 z-50 m-auto grid h-fit w-[calc(100%-2rem)] max-w-lg gap-4 rounded-floating border border-border bg-popover p-6 text-popover-foreground outline-none max-h-[calc(100dvh-2rem)] overflow-y-auto transition-opacity duration-150 ease-nq data-starting-style:opacity-0 data-ending-style:opacity-0">
            <form novalidate data-slot="api-key-create" class="grid gap-4" x-on:submit.prevent="submit()">
                <div data-slot="dialog-header" class="flex flex-col gap-1.5 pe-8 text-start"><h2 data-slot="dialog-title" :id="$id('nq-dialog', 'title')" class="text-h3 text-foreground">Create an API key</h2>
                    <p data-slot="dialog-description" :id="$id('nq-dialog', 'description')" class="text-body-sm text-muted-foreground">Name it after where it will be used. You will see the key once.</p></div>
                <template x-if="formError"><div data-slot="alert" data-tone="danger" role="alert"
        class="relative grid grid-cols-[auto_1fr_auto] items-start gap-x-3 rounded-card border p-3 text-start border-nq-danger/30 bg-nq-danger-soft">
    <svg aria-hidden="true" data-slot="alert-icon" class="mt-0.5 size-4 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>    <div data-slot="alert-body" class="flex min-w-0 flex-col gap-0.5">
                            <div data-slot="alert-description" class="text-body-sm text-foreground"><span x-text="formError"></span></div>
            </div>
    </div>
</template>
                <div data-slot="field" x-data="nqField(false)" x-modelable="invalid" x-id="['nq-field']"
         data-valid     x-model="nameInvalid" class="flex flex-col gap-1.5">
    <label data-slot="field-label"  class="text-label text-foreground data-disabled:opacity-50">Name</label>
                    <input data-slot="input" type="text"
                    x-model="draftName" placeholder="Production server" autocomplete="off" maxlength="60" class="w-full min-w-0 rounded-control border border-input bg-card px-3 text-body text-foreground min-h-[var(--nq-touch-min,0px)] transition-colors duration-150 ease-nq outline-none placeholder:text-muted-foreground focus-visible:border-nq-focus focus-visible:outline-1 focus-visible:outline-nq-focus data-invalid:border-nq-danger aria-invalid:border-nq-danger disabled:cursor-not-allowed disabled:opacity-50 pointer-coarse:text-[16px] h-control">
                    <div data-slot="field-error" role="alert" x-show="invalid"  style="display: none"  class="text-caption text-nq-danger-text">Give the key a name.</div>
</div>
                <fieldset class="grid gap-2 border-0 p-0" aria-describedby="nq-api-key-000001-scopes">
                    <legend class="mb-1 text-label text-foreground">Scopes</legend>
                    <p id="nq-api-key-000001-scopes" class="text-caption text-muted-foreground">The key can do only what these allow.</p>
                    <ul class="grid gap-1 rounded-card border border-border p-2">
                                                    <li class="flex items-start gap-2.5 rounded-control px-2 py-1.5 hover:bg-nq-hover">
                                <button type="button" role="checkbox" data-slot="checkbox" x-data="nqCheckbox(false, false)" x-modelable="checked" x-bind="root"
    aria-checked="false"
     data-unchecked                 id="nq-api-key-000001-read" x-model="picked[0]" class="relative inline-flex size-4 shrink-0 items-center justify-center rounded-[4px] border border-nq-line-strong bg-card text-primary-foreground outline-none transition-colors duration-150 ease-nq data-checked:border-primary data-checked:bg-primary data-indeterminate:border-primary data-indeterminate:bg-primary focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-nq-focus data-disabled:cursor-not-allowed data-disabled:opacity-50 after:absolute after:-inset-1 mt-0.5">
    <span data-slot="checkbox-indicator" class="flex items-center justify-center [&_svg]:size-3 [&_svg]:stroke-3" x-show="checked || indeterminate"  style="display: none" >
        <svg aria-hidden="true" x-show="indeterminate" style="display: none" 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="M5 12h14"/>
</svg>        <svg aria-hidden="true" x-show="! indeterminate" style="" 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="M20 6 9 17l-5-5"/>
</svg>    </span>
    </button>
                                <label for="nq-api-key-000001-read" class="grid min-w-0 flex-1 cursor-pointer gap-0.5">
                                    <span class="text-body-sm text-foreground">Read</span>
                                    <span class="text-caption text-muted-foreground">List and fetch records</span>                                </label>
                            </li>
                                                    <li class="flex items-start gap-2.5 rounded-control px-2 py-1.5 hover:bg-nq-hover">
                                <button type="button" role="checkbox" data-slot="checkbox" x-data="nqCheckbox(false, false)" x-modelable="checked" x-bind="root"
    aria-checked="false"
     data-unchecked                 id="nq-api-key-000001-write" x-model="picked[1]" class="relative inline-flex size-4 shrink-0 items-center justify-center rounded-[4px] border border-nq-line-strong bg-card text-primary-foreground outline-none transition-colors duration-150 ease-nq data-checked:border-primary data-checked:bg-primary data-indeterminate:border-primary data-indeterminate:bg-primary focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-nq-focus data-disabled:cursor-not-allowed data-disabled:opacity-50 after:absolute after:-inset-1 mt-0.5">
    <span data-slot="checkbox-indicator" class="flex items-center justify-center [&_svg]:size-3 [&_svg]:stroke-3" x-show="checked || indeterminate"  style="display: none" >
        <svg aria-hidden="true" x-show="indeterminate" style="display: none" 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="M5 12h14"/>
</svg>        <svg aria-hidden="true" x-show="! indeterminate" style="" 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="M20 6 9 17l-5-5"/>
</svg>    </span>
    </button>
                                <label for="nq-api-key-000001-write" class="grid min-w-0 flex-1 cursor-pointer gap-0.5">
                                    <span class="text-body-sm text-foreground">Write</span>
                                    <span class="text-caption text-muted-foreground">Create and change records</span>                                </label>
                            </li>
                                            </ul>
                    <p role="alert" x-show="scopesInvalid" style="display: none" class="text-caption text-nq-danger-text">Pick at least one scope.</p>
                </fieldset>
                <div data-slot="field" x-data="nqField(false)" x-modelable="invalid" x-id="['nq-field']"
         data-valid     class="flex flex-col gap-1.5">
    <label data-slot="field-label"  class="text-label text-foreground data-disabled:opacity-50">Expires</label>
                    <div data-slot="select" x-data="nqSelect('90', false)" x-modelable="value" x-id="['nq-select']" x-model="expiry" class="contents">
    <button data-slot="select-trigger" x-ref="trigger" x-bind="trigger"
        class="flex h-control w-full min-w-0 items-center justify-between gap-2 rounded-control border border-input bg-card px-3 text-body text-foreground min-h-[var(--nq-touch-min,0px)] cursor-default select-none outline-none transition-colors duration-150 ease-nq focus-visible:border-nq-focus focus-visible:outline-1 focus-visible:outline-nq-focus data-popup-open:border-nq-focus data-invalid:border-nq-danger disabled:cursor-not-allowed disabled:opacity-50 pointer-coarse:text-[16px]">
    <span data-slot="select-value" x-text="label() ?? ''" :data-placeholder="empty() ? '' : undefined"
    class="min-w-0 flex-1 truncate text-start data-placeholder:text-muted-foreground"></span>
    <span class="flex shrink-0 text-muted-foreground [&_svg]:size-4"><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 15 5 5 5-5"/>
  <path d="m7 9 5-5 5 5"/>
</svg></span>
</button>
                        <template x-teleport="body">
    <div data-slot="select-content" x-ref="popup" x-bind="popup" x-nq-presence="open" x-anchor.bottom-start.offset.4="$refs.trigger"
        class="z-50 min-w-[var(--anchor-width)] max-h-[var(--available-height)] overflow-y-auto rounded-floating border border-border bg-popover p-1.5 text-popover-foreground shadow-floating outline-none transition-opacity duration-150 ease-nq data-starting-style:opacity-0 data-ending-style:opacity-0">
        <div data-slot="select-item" x-bind="item('7', false)"
    class="relative flex h-nav-row min-h-[var(--nq-touch-min,0px)] cursor-default select-none items-center gap-2.5 rounded-control ps-8 pe-2.5 text-body-sm text-foreground outline-none data-highlighted:bg-nq-selected data-disabled:pointer-events-none data-disabled:opacity-50">
    <span aria-hidden="true" class="absolute start-2.5 inline-flex size-4 items-center justify-center">
        <span x-show="isSelected('7')" x-cloak class="contents"><svg class="size-4" 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="M20 6 9 17l-5-5"/>
</svg></span>
    </span>
    <span data-slot="select-item-text" class="min-w-0 flex-1 truncate">In 7 days</span>
</div>
                                                            <div data-slot="select-item" x-bind="item('30', false)"
    class="relative flex h-nav-row min-h-[var(--nq-touch-min,0px)] cursor-default select-none items-center gap-2.5 rounded-control ps-8 pe-2.5 text-body-sm text-foreground outline-none data-highlighted:bg-nq-selected data-disabled:pointer-events-none data-disabled:opacity-50">
    <span aria-hidden="true" class="absolute start-2.5 inline-flex size-4 items-center justify-center">
        <span x-show="isSelected('30')" x-cloak class="contents"><svg class="size-4" 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="M20 6 9 17l-5-5"/>
</svg></span>
    </span>
    <span data-slot="select-item-text" class="min-w-0 flex-1 truncate">In 30 days</span>
</div>
                                                            <div data-slot="select-item" x-bind="item('90', false)"
    class="relative flex h-nav-row min-h-[var(--nq-touch-min,0px)] cursor-default select-none items-center gap-2.5 rounded-control ps-8 pe-2.5 text-body-sm text-foreground outline-none data-highlighted:bg-nq-selected data-disabled:pointer-events-none data-disabled:opacity-50">
    <span aria-hidden="true" class="absolute start-2.5 inline-flex size-4 items-center justify-center">
        <span x-show="isSelected('90')" x-cloak class="contents"><svg class="size-4" 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="M20 6 9 17l-5-5"/>
</svg></span>
    </span>
    <span data-slot="select-item-text" class="min-w-0 flex-1 truncate">In 90 days</span>
</div>
                                                            <div data-slot="select-item" x-bind="item('365', false)"
    class="relative flex h-nav-row min-h-[var(--nq-touch-min,0px)] cursor-default select-none items-center gap-2.5 rounded-control ps-8 pe-2.5 text-body-sm text-foreground outline-none data-highlighted:bg-nq-selected data-disabled:pointer-events-none data-disabled:opacity-50">
    <span aria-hidden="true" class="absolute start-2.5 inline-flex size-4 items-center justify-center">
        <span x-show="isSelected('365')" x-cloak class="contents"><svg class="size-4" 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="M20 6 9 17l-5-5"/>
</svg></span>
    </span>
    <span data-slot="select-item-text" class="min-w-0 flex-1 truncate">In 1 year</span>
</div>
                                                            <div data-slot="select-item" x-bind="item('never', false)"
    class="relative flex h-nav-row min-h-[var(--nq-touch-min,0px)] cursor-default select-none items-center gap-2.5 rounded-control ps-8 pe-2.5 text-body-sm text-foreground outline-none data-highlighted:bg-nq-selected data-disabled:pointer-events-none data-disabled:opacity-50">
    <span aria-hidden="true" class="absolute start-2.5 inline-flex size-4 items-center justify-center">
        <span x-show="isSelected('never')" x-cloak class="contents"><svg class="size-4" 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="M20 6 9 17l-5-5"/>
</svg></span>
    </span>
    <span data-slot="select-item-text" class="min-w-0 flex-1 truncate">Never</span>
</div>
    </div>
</template>
    </div>
</div>
                <div data-slot="dialog-footer" class="flex flex-col-reverse gap-2 sm:flex-row sm:justify-end"><button data-slot="button"
     type="button"                         x-on:click="createOpen = false" x-bind:disabled="pending ? &#039;&#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 text-foreground hover:bg-nq-hover h-control px-[var(--nq-control-pad)]">
        Cancel</button>
                    <button data-slot="button"
     type="submit"                         x-bind:aria-busy="pending ? &#039;true&#039; : null" x-bind:data-disabled="pending ? &#039;&#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 px-[var(--nq-control-pad)]">
        <svg data-slot="spinner" aria-hidden="true" style="display: none;" x-show="pending" class="size-4 animate-spin motion-reduce:animate-none" 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="M21 12a9 9 0 1 1-6.219-8.56"/>
</svg>                        Create key</button></div>
            </form>
                            <button type="button" data-slot="dialog-close" x-on:click="close()" aria-label="Close"
                    class="absolute end-3 top-3 inline-flex size-8 items-center justify-center rounded-control text-muted-foreground transition-colors duration-150 hover:bg-nq-hover hover:text-foreground focus-visible:outline-2 focus-visible:outline-nq-focus [&_svg]:size-4"><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="M18 6 6 18"/>
  <path d="m6 6 12 12"/>
</svg></button>
                    </div>
    </div>
</template>
</div>
    <div data-slot="dialog" x-data="nqDialog(false)" x-modelable="open" x-id="['nq-dialog']" x-model="revealOpen" class="contents">
    <template x-teleport="body">
    <div data-slot="dialog-portal">
        <div data-slot="dialog-backdrop" x-nq-presence="open" x-on:click="close()" class="fixed inset-0 z-50 bg-nq-fg/15 dark:bg-nq-bg/60 transition-opacity duration-150 ease-nq data-starting-style:opacity-0 data-ending-style:opacity-0"></div>
        <div data-slot="dialog-content" x-bind="popup" x-nq-presence="open" x-trap.noscroll="open"
            class="fixed inset-0 z-50 m-auto grid h-fit w-[calc(100%-2rem)] max-w-lg gap-4 rounded-floating border border-border bg-popover p-6 text-popover-foreground outline-none max-h-[calc(100dvh-2rem)] overflow-y-auto transition-opacity duration-150 ease-nq data-starting-style:opacity-0 data-ending-style:opacity-0">
            <div data-slot="api-key-reveal" class="contents">
            <div data-slot="dialog-header" class="flex flex-col gap-1.5 pe-8 text-start"><h2 data-slot="dialog-title" :id="$id('nq-dialog', 'title')" class="text-h3 text-foreground"><span x-text="secretTitle"></span></h2>
                <p data-slot="dialog-description" :id="$id('nq-dialog', 'description')" class="text-body-sm text-muted-foreground">This is the only time the full key is shown. Store it in a secret manager. If you lose it, rotate the key.</p></div>
            <div data-slot="alert" data-tone="warning" role="alert"
        class="relative grid grid-cols-[auto_1fr_auto] items-start gap-x-3 rounded-card border p-3 text-start border-nq-warning/30 bg-nq-warning-soft">
    <svg aria-hidden="true" data-slot="alert-icon" class="mt-0.5 size-4 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>    <div data-slot="alert-body" class="flex min-w-0 flex-col gap-0.5">
                            <div data-slot="alert-description" class="text-body-sm text-foreground">You will not see this key again.</div>
            </div>
    </div>
            <div data-slot="copy-field" class="contents">
                <div role="group" data-slot="input-group"
    class="group/input-group flex h-control min-h-[var(--nq-touch-min,0px)] w-full min-w-0 items-center overflow-hidden rounded-control border border-input bg-card text-body text-foreground transition-colors duration-150 ease-nq focus-within:border-nq-focus focus-within:outline-1 focus-within:outline-nq-focus has-[[data-invalid]]:border-nq-danger has-[[aria-invalid=true]]:border-nq-danger has-[input:disabled]:cursor-not-allowed has-[input:disabled]:opacity-50"><input data-slot="input-group-input"  dir="ltr"     readonly="readonly" aria-label="Secret key" x-bind:value="secret" x-on:focus="$el.select()" class="h-full min-w-0 flex-1 border-0 bg-transparent px-3 text-body text-foreground outline-none placeholder:text-muted-foreground disabled:cursor-not-allowed pointer-coarse:text-[16px] text-start" />
                    <div data-slot="input-group-addon" data-align="end"
    class="flex h-full shrink-0 items-center gap-1.5 text-body-sm text-muted-foreground [&_svg]:size-4 order-last ps-1 pe-3"><button data-slot="copy-button"
     type="button"                         aria-label="Copy" x-on:click="copySecret()" x-bind:data-copied="copied ? &#039;&#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 text-foreground hover:bg-nq-hover size-control-sm p-0 data-copied:text-nq-success-text">
        <svg aria-hidden="true" x-show="!copied" 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">
  <rect width="14" height="14" x="8" y="8" rx="2" ry="2"/>
  <path d="M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2"/>
</svg>                            <svg aria-hidden="true" x-show="copied" style="display: none" 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="M20 6 9 17l-5-5"/>
</svg></button></div></div>
            </div>
            <span role="status" aria-live="polite" class="sr-only" x-text="copied ? 'Copied to clipboard' : ''"></span>
            <div data-slot="dialog-footer" class="flex flex-col-reverse gap-2 sm:flex-row sm:justify-end"><button data-slot="button"
     type="button"                         x-on:click="revealOpen = false" 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 px-[var(--nq-control-pad)]">
        Done</button></div>
            </div>
                    </div>
    </div>
</template>
</div>
</div>
```
