# EnvList

> A .env manager with masked values, reveal and copy, add edit delete, import by pasting a .env, export, per-environment tabs and key validation.

Source: https://docs.nasaqui.com/components/env-list

## Install

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

Manages environment variables as key and value rows. Values are masked with a fixed-width mask (so length is not
leaked) and only enter the DOM while revealed; a revealed value hides again after 30 seconds. Each row has reveal,
copy, edit and delete. Add and edit open a dialog that checks the key (empty, invalid, duplicate). Import takes a
pasted `.env` or a chosen file, shows what was found, flags conflicts and unreadable lines, and lets the user
choose whether to overwrite. Export downloads a `.env`. Optional tabs switch environments. Nothing is logged, and
error messages never include a value. Presentational: your callbacks talk to the backend.

## When to use

- Project or service settings where a developer edits environment variables.

## When not to use

- API keys with a create-once, show-once flow: use [ApiKeys](https://docs.nasaqui.com/components/api-keys).
- A single value to copy: use `CopyField` from [copy-button](https://docs.nasaqui.com/components/copy-button).

## Import

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

## Quick start

```tsx
import { EnvList } from "@fadymondy/nasaq/web";

export function Env() {
  return (
    <EnvList
      variables={[{ key: "DATABASE_URL", value: "postgres://...", secret: true }]}
      onSave={async (v, previousKey) => {}}
      onDelete={async (key) => {}}
      onImport={async (vars, { overwrite }) => {}}
    />
  );
}
```

## Anatomy

```
EnvList         data-slot="env-list"          <section>
├─ header       title, description, environment tabs, Add / Import / Copy / Download
├─ filter       search, shown when there are more than 5 variables
├─ rows         data-slot="env-row"           key, masked value, reveal, copy, edit, delete
├─ add / edit   Dialog                        key and value, validation, secret switch
├─ import       Dialog                        paste or file, preview, overwrite checkbox, issues
└─ delete       AlertDialog                   confirm
```

## API

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `variables` | `EnvVariable[]` | required | `{ key, value, secret?, description? }`. `secret` defaults to true. |
| `title?` / `description?` | `ReactNode` | "Environment variables" | Header text. |
| `environments?` | `{ id, label }[]` | none | Tabs. Load the matching `variables` when `onEnvironmentChange` fires. |
| `environment?` / `onEnvironmentChange?` | `string` / `(id) => void` | first | Selected environment. |
| `onSave?` | `(variable, previousKey?) => Promise<{ error? } \| void>` | none | Add (no `previousKey`) or edit. `{ error }` keeps the dialog open. |
| `onDelete?` | `(key) => Promise<{ error? } \| void>` | none | After confirmation. |
| `onImport?` | `(variables, { overwrite }) => Promise<{ error? } \| void>` | none | Imported values are secret unless the key is public (`NEXT_PUBLIC_*`, `VITE_*`). |
| `onExport?` | `(variables) => void` | saves a file | Replaces the default download. |
| `exportFilename?` | `string` | `".env"` | Default download name. |
| `revealTimeout?` | `number` | `30000` | Milliseconds until a revealed value hides. `0` keeps it. |
| `readOnly?` | `boolean` | `false` | No add, edit, delete or import. Reveal and copy still work. |
| `labels?` | `Partial<EnvListLabels>` | built-in en/ar | Translations. |

Helpers: `parseEnv(text)` returns `{ variables, duplicates, issues }` (issues carry a line number and a problem,
never a value), `serializeEnv`, `quoteEnvValue`, `checkEnvKey`, `isValidEnvKey`, `conflictingKeys`, `looksPublic`, `MASK`.

## Examples

### Environments

```tsx
<EnvList
  environments={[{ id: "dev", label: "Development" }, { id: "prod", label: "Production" }]}
  environment={env}
  onEnvironmentChange={setEnv}
  variables={byEnv[env]}
/>
```

### Parsing

```ts
parseEnv('A=1\nexport B="two words"\nA=3').duplicates; // ["A"], the last value wins
```

## Accessibility

| Key | Action |
| --- | --- |
| `Tab` | Row buttons in order |
| `Enter` / `Space` | Reveal, copy, edit or delete |
| `Esc` | Closes a dialog |

- Reveal is a toggle button with `aria-pressed` and a name that includes the key. Masked values are `aria-hidden` text plus the button label, so a mask is never read out as twelve bullets.
- Validation messages are tied to the key field with `aria-describedby` and announced.
- Delete asks first, in an alert dialog that names the key.

## RTL & i18n

- Keys and values are `dir="ltr"` inside Arabic pages; the chrome follows the page.
- Built-in Arabic strings; override with `labels`.
- Buttons sit on the logical inline-end side.

## Styling & tokens

- Rows use `bg-card`, `border-border`, `text-code` for keys and values; conflict and issue text uses `text-nq-warning-text` and `text-nq-danger-text`.
- Slots: `env-list`, `env-row`. `data-revealed` on a row.

## Do / Don't

- **Do** keep values out of logs, analytics and error messages, in your callbacks too.
- **Do** return `{ error }` with a safe message from callbacks.
- **Don't** render this for people who should not see secrets: masking is not access control.
- **Don't** use `revealTimeout={0}` on shared screens.

## Related

- [ApiKeys](https://docs.nasaqui.com/components/api-keys) · [CodeBlock variants](https://docs.nasaqui.com/components/code-block-variants) · [Dialog](https://docs.nasaqui.com/components/dialog) · [AlertDialog](https://docs.nasaqui.com/components/alert-dialog)

## Lab

https://docs.nasaqui.com/?path=/docs/components-developer-tools-env-list--docs

## Code

### React

```tsx
import { EnvList } from "@fadymondy/nasaq/web";

export function Env() {
  return (
    <EnvList
      variables={[{ key: "DATABASE_URL", value: "postgres://...", secret: true }]}
      onSave={async (v, previousKey) => {}}
      onDelete={async (key) => {}}
      onImport={async (vars, { overwrite }) => {}}
    />
  );
}
```

### shadcn

```tsx
import { EnvList } from "@/components/ui/env-list";

export function Env() {
  return (
    <EnvList
      variables={[{ key: "DATABASE_URL", value: "postgres://...", secret: true }]}
      onSave={async (v, previousKey) => {}}
      onDelete={async (key) => {}}
      onImport={async (vars, { overwrite }) => {}}
    />
  );
}
```

### Vue

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

const variables = ref<EnvVariable[]>([
  { key: "DATABASE_URL", value: "postgres://app:s3cret@db.internal/app", secret: true },
  { key: "VITE_API_URL", value: "https://api.example.com", secret: false, description: "Public base URL" },
]);

// Run the work, then pass the new `variables` back. Resolve with `{ error }` to keep the dialog open with a message.
async function onSave(variable: EnvVariable, previousKey?: string) {
  variables.value = previousKey ? variables.value.map((v) => (v.key === previousKey ? variable : v)) : [...variables.value, variable];
}
async function onDelete(key: string) {
  variables.value = variables.value.filter((v) => v.key !== key);
}
async function onImport(incoming: EnvVariable[], { overwrite }: { overwrite: boolean }) {
  const have = new Set(variables.value.map((v) => v.key));
  const next = variables.value.map((v) => (overwrite ? (incoming.find((i) => i.key === v.key) ?? v) : v));
  variables.value = [...next, ...incoming.filter((i) => !have.has(i.key))];
}
</script>

<template>
  <NqEnvList :variables="variables" :on-save="onSave" :on-delete="onDelete" :on-import="onImport" />
</template>
```

### Blade

```blade
<div x-data
    x-on:nq-save="$event.detail.wait(new Promise((resolve) => setTimeout(resolve, 400)))"
    x-on:nq-delete="$event.detail.wait(new Promise((resolve) => setTimeout(resolve, 400)))"
    x-on:nq-import="$event.detail.wait(new Promise((resolve) => setTimeout(resolve, 400)))">
    <x-nq::env-list
        :variables="[
            ['key' => 'DATABASE_URL', 'value' => 'postgres://app:s3cret@db.internal:5432/app', 'secret' => true],
            ['key' => 'VITE_API_URL', 'value' => 'https://api.example.com', 'secret' => false, 'description' => 'Public API origin'],
        ]" />
</div>
```

### HTML + Alpine

```html
<div x-data
    x-on:nq-save="$event.detail.wait(new Promise((resolve) => setTimeout(resolve, 400)))"
    x-on:nq-delete="$event.detail.wait(new Promise((resolve) => setTimeout(resolve, 400)))"
    x-on:nq-import="$event.detail.wait(new Promise((resolve) => setTimeout(resolve, 400)))">
    <section data-slot="env-list" aria-label="Environment variables" x-data="nqEnvList(JSON.parse('{\u0022variables\u0022:[{\u0022key\u0022:\u0022DATABASE_URL\u0022,\u0022value\u0022:\u0022postgres:\\\/\\\/app:s3cret@db.internal:5432\\\/app\u0022,\u0022secret\u0022:true},{\u0022key\u0022:\u0022VITE_API_URL\u0022,\u0022value\u0022:\u0022https:\\\/\\\/api.example.com\u0022,\u0022secret\u0022:false,\u0022description\u0022:\u0022Public API origin\u0022}],\u0022environment\u0022:null,\u0022revealTimeout\u0022:30000,\u0022exportFilename\u0022:\u0022.env\u0022,\u0022strings\u0022:{\u0022reveal\u0022:\u0022Reveal {key}\u0022,\u0022hide\u0022:\u0022Hide {key}\u0022,\u0022copyValue\u0022:\u0022Copy value of {key}\u0022,\u0022edit\u0022:\u0022Edit {key}\u0022,\u0022remove\u0022:\u0022Delete {key}\u0022,\u0022emptyValue\u0022:\u0022(empty)\u0022,\u0022countOne\u0022:\u00221 variable\u0022,\u0022countMany\u0022:\u0022{n} variables\u0022,\u0022addTitle\u0022:\u0022Add variable\u0022,\u0022editTitle\u0022:\u0022Edit {key}\u0022,\u0022keyEmpty\u0022:\u0022Enter a name.\u0022,\u0022keyInvalid\u0022:\u0022Use only letters, digits and underscores, and do not start with a digit.\u0022,\u0022keyDuplicate\u0022:\u0022A variable with this name already exists.\u0022,\u0022genericError\u0022:\u0022Something went wrong. Try again.\u0022,\u0022foundOne\u0022:\u00221 variable found\u0022,\u0022foundMany\u0022:\u0022{n} variables found\u0022,\u0022conflictsOne\u0022:\u00221 already exists\u0022,\u0022conflictsMany\u0022:\u0022{n} already exist\u0022,\u0022pasteDuplicates\u0022:\u0022Repeated in the paste, last value wins: {keys}\u0022,\u0022issueInvalidKey\u0022:\u0022Line {line}: \\u0022{key}\\u0022 is not a valid name\u0022,\u0022issueUnterminatedQuote\u0022:\u0022Line {line}: quote is never closed{key}\u0022,\u0022issueNoEquals\u0022:\u0022Line {line}: expected NAME=value\u0022,\u0022importOne\u0022:\u0022Import 1 variable\u0022,\u0022importMany\u0022:\u0022Import {n} variables\u0022,\u0022deleteTitle\u0022:\u0022Delete {key}?\u0022,\u0022copied\u0022:\u0022Copied to clipboard\u0022}}'))" class="flex min-w-0 flex-col gap-4">
    <header class="flex flex-wrap items-start justify-between gap-3">
        <div class="flex min-w-0 flex-col gap-1">
            <h3 class="text-h3 text-foreground">Environment variables</h3>
            <p class="text-body-sm text-muted-foreground">Values are hidden until you reveal them.</p>
        </div>
        <div class="flex flex-wrap items-center gap-2">
                            <button data-slot="button"
     type="button"                         x-on:click="openImport()" 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="M12 3v12"/>
  <path d="m17 8-5-5-5 5"/>
  <path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"/>
</svg>                    Import .env</button>
                        <button data-slot="copy-button"
     type="button"                         x-bind:disabled="variables.length === 0" x-bind:data-copied="copiedAll ? &#039;&#039; : null" x-on:click="copyAll()" 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" x-show="! copiedAll" 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="copiedAll" 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>                Copy as .env</button>
            <span data-slot="copy-button-status" role="status" aria-live="polite" class="sr-only" x-text="copied ? 'Copied to clipboard' : ''"></span>
            <button data-slot="button"
     type="button"                         x-bind:disabled="variables.length === 0" x-on:click="download()" 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="M12 15V3"/>
  <path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"/>
  <path d="m7 10 5 5 5-5"/>
</svg>                Download .env</button>
                            <button data-slot="button"
     type="button"                         x-on:click="openEdit(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">
        <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>                    Add variable</button>
                    </div>
    </header>
    <div role="group" data-slot="input-group"
    x-show="variables.length &gt; 5" style="display: none" 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 max-w-sm"><div data-slot="input-group-addon" data-align="start"
    class="flex h-full shrink-0 items-center gap-1.5 text-body-sm text-muted-foreground [&_svg]:size-4 order-first ps-3 pe-1"><svg aria-hidden="true" class="size-4 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">
  <path d="m21 21-4.34-4.34"/>
  <circle cx="11" cy="11" r="8"/>
</svg></div>
        <input data-slot="input-group-input"  dir="ltr"     x-model="filter" type="search" placeholder="Filter variables" aria-label="Filter variables" 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>
    <div x-show="variables.length === 0"  style="display: none" >
        <div data-slot="empty-state" class="flex flex-col items-center justify-center gap-3 border border-dashed border-border px-6 py-12 text-center rounded-card">
            <span data-slot="state-icon" class="inline-flex size-10 items-center justify-center rounded-control border border-border bg-card [&amp;_svg]:size-5 text-muted-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">
  <polyline points="22 12 16 12 14 15 10 15 8 12 2 12"/>
  <path d="M5.45 5.11 2 12v6a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2v-6l-3.45-6.89A2 2 0 0 0 16.76 4H7.24a2 2 0 0 0-1.79 1.11z"/>
</svg>        </span>
        <div class="flex max-w-sm flex-col gap-1">
        <p class="text-label text-foreground">No variables yet</p>
                    <p class="text-body-sm text-muted-foreground">Add one by hand or paste the contents of a .env file.</p>
            </div>
            <div class="mt-1 flex flex-wrap items-center justify-center gap-2"><button data-slot="button"
     type="button"                         x-on:click="openEdit(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 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>                        Add variable</button>
                                                    <button data-slot="button"
     type="button"                         x-on:click="openImport()" 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)]">
        <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="M6 22a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h8a2.4 2.4 0 0 1 1.704.706l3.588 3.588A2.4 2.4 0 0 1 20 8v12a2 2 0 0 1-2 2z"/>
  <path d="M14 2v5a1 1 0 0 0 1 1h5"/>
  <path d="M12 12v6"/>
  <path d="m15 15-3-3-3 3"/>
</svg>                        Import .env</button></div>
    </div>
    </div>
    <div class="contents" x-show="variables.length > 0" >
        <ul aria-label="Variables" class="m-0 flex list-none flex-col overflow-hidden rounded-card border border-border bg-card p-0">
            <template x-for="v in shown" x-bind:key="v.key">
                <li data-slot="env-row" x-bind:data-secret="isSecret(v) ? '' : null" x-bind:data-revealed="revealed[v.key] ? '' : null"
                    class="flex flex-col gap-2 border-b border-border px-4 py-3 last:border-b-0 sm:flex-row sm:items-center sm:gap-4">
                    <div class="flex min-w-0 flex-col gap-0.5 sm:w-2/5">
                        <div class="flex min-w-0 items-center gap-2">
                            <bdi dir="ltr" class="truncate font-mono text-code font-medium text-foreground" x-text="v.key"></bdi>
                            <span data-slot="badge"     x-show="isSecret(v)" class="inline-flex h-5 items-center gap-1 whitespace-nowrap rounded-[4px] border px-1.5 text-caption font-medium [&_svg]:size-3 border-border bg-secondary text-foreground shrink-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">
  <rect width="18" height="11" x="3" y="11" rx="2" ry="2"/>
  <path d="M7 11V7a5 5 0 0 1 10 0v4"/>
</svg>Secret</span>
                        </div>
                        <span class="truncate text-caption text-muted-foreground" x-show="v.description" x-text="v.description"></span>
                    </div>
                    <div class="min-w-0 flex-1">
                        <bdi dir="ltr" data-slot="env-value" class="block truncate font-mono text-code text-foreground" x-show="isVisible(v)"
                            x-bind:title="isVisible(v) ? v.value : null" x-bind:class="v.value === '' ? 'text-muted-foreground' : ''" x-text="valueText(v)"></bdi>
                        <span data-slot="env-value" dir="ltr" role="text" aria-label="Value hidden" class="block font-mono text-code text-muted-foreground" x-show="! isVisible(v)">••••••••••••</span>
                    </div>
                    <div class="flex shrink-0 items-center gap-0.5">
                        <button data-slot="button"
     type="button"                         x-show="isSecret(v)" x-bind:aria-label="rowLabel(revealed[v.key] ? &#039;hide&#039; : &#039;reveal&#039;, v)" x-bind:aria-pressed="revealed[v.key] ? &#039;true&#039; : &#039;false&#039;" x-on:click="toggle(v.key)" 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">
        <svg aria-hidden="true" x-show="revealed[v.key]" 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="M10.733 5.076a10.744 10.744 0 0 1 11.205 6.575 1 1 0 0 1 0 .696 10.747 10.747 0 0 1-1.444 2.49"/>
  <path d="M14.084 14.158a3 3 0 0 1-4.242-4.242"/>
  <path d="M17.479 17.499a10.75 10.75 0 0 1-15.417-5.151 1 1 0 0 1 0-.696 10.75 10.75 0 0 1 4.446-5.143"/>
  <path d="m2 2 20 20"/>
</svg>                            <svg aria-hidden="true" x-show="! revealed[v.key]" 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="M2.062 12.348a1 1 0 0 1 0-.696 10.75 10.75 0 0 1 19.876 0 1 1 0 0 1 0 .696 10.75 10.75 0 0 1-19.876 0"/>
  <circle cx="12" cy="12" r="3"/>
</svg></button>
                        <button data-slot="copy-button"
     type="button"                         x-bind:aria-label="rowLabel(&#039;copyValue&#039;, v)" x-bind:data-copied="copied === v.key ? &#039;&#039; : null" x-on:click="copyValue(v)" 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 !== v.key" 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 === v.key" 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>
                                                    <button data-slot="button"
     type="button"                         x-bind:aria-label="rowLabel(&#039;edit&#039;, v)" x-on:click="openEdit(v.key)" 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">
        <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="M21.174 6.812a1 1 0 0 0-3.986-3.987L3.842 16.174a2 2 0 0 0-.5.83l-1.321 4.352a.5.5 0 0 0 .623.622l4.353-1.32a2 2 0 0 0 .83-.497z"/>
  <path d="m15 5 4 4"/>
</svg></button>
                                                                            <button data-slot="button"
     type="button"                         x-bind:aria-label="rowLabel(&#039;remove&#039;, v)" x-on:click="askDelete(v.key)" 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 hover:bg-nq-hover size-control-sm p-0 text-nq-danger-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">
  <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></button>
                                            </div>
                </li>
            </template>
            <li class="px-4 py-6 text-center text-body-sm text-muted-foreground" x-show="shown.length === 0" style="display: none">No variables match your filter.</li>
        </ul>
        <p class="text-caption text-muted-foreground" data-slot="env-count" x-text="countLabel"></p>
    </div>
            <div data-slot="dialog" x-data="nqDialog(false)" x-modelable="open" x-id="['nq-dialog']" x-model="editOpen" 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 data-slot="env-variable-dialog" class="grid gap-4" novalidate x-on:submit.prevent="submitEdit()">
                    <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="dialogTitle"></span></h2>
                        <p data-slot="dialog-description" :id="$id('nq-dialog', 'description')" class="text-body-sm text-muted-foreground">Letters, digits and underscores. Cannot start with a digit.</p></div>
                    <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">Name</label>
                        <input data-slot="input" type="text"
     dir="ltr"                 x-model.trim="form.key" autocapitalize="off" autocomplete="off" autocorrect="off" spellcheck="false" placeholder="DATABASE_URL" x-bind:data-invalid="showProblem ? &#039;&#039; : null" x-bind:aria-invalid="showProblem ? &#039;true&#039; : null" x-on:blur="touched = true" class="w-full min-w-0 rounded-control border border-input bg-card px-3 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 text-start font-mono text-code">
                        <p role="alert" class="text-caption text-nq-danger-text" x-show="showProblem" style="display: none" x-text="keyMessage"></p>
</div>
                    <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">Value</label>
                        <textarea data-slot="textarea"
                x-model="form.value" dir="ltr" rows="3" autocapitalize="off" autocomplete="off" autocorrect="off" spellcheck="false" x-bind:class="form.secret &amp;&amp; ! showValue ? &#039;[-webkit-text-security:disc]&#039; : &#039;&#039;" class="w-full min-w-0 rounded-control border border-input bg-card px-3 text-foreground 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] py-2 min-h-20 font-mono text-code text-start"></textarea>
                        <button type="button" x-show="form.secret" x-bind:aria-pressed="showValue ? 'true' : 'false'" data-slot="env-show-value"
                            class="inline-flex w-fit items-center gap-1 text-caption text-muted-foreground underline underline-offset-4 outline-none hover:text-foreground focus-visible:outline-2 focus-visible:outline-nq-focus"
                            x-on:click="showValue = ! showValue">
                            <svg aria-hidden="true" x-show="showValue" style="display: none" class="size-3.5" 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.733 5.076a10.744 10.744 0 0 1 11.205 6.575 1 1 0 0 1 0 .696 10.747 10.747 0 0 1-1.444 2.49"/>
  <path d="M14.084 14.158a3 3 0 0 1-4.242-4.242"/>
  <path d="M17.479 17.499a10.75 10.75 0 0 1-15.417-5.151 1 1 0 0 1 0-.696 10.75 10.75 0 0 1 4.446-5.143"/>
  <path d="m2 2 20 20"/>
</svg>                            <svg aria-hidden="true" x-show="! showValue" class="size-3.5" 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="M2.062 12.348a1 1 0 0 1 0-.696 10.75 10.75 0 0 1 19.876 0 1 1 0 0 1 0 .696 10.75 10.75 0 0 1-19.876 0"/>
  <circle cx="12" cy="12" r="3"/>
</svg>                            Show value
                        </button>
</div>
                    <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">Note (optional)</label>
                        <input data-slot="input" type="text"
                    x-model="form.note" autocomplete="off" 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>
                    <div class="flex items-start justify-between gap-4 rounded-control border border-border p-3">
                        <div class="flex flex-col gap-0.5">
                            <label for="nq-env-000001-secret" class="text-label text-foreground">Secret</label>
                            <span class="text-caption text-muted-foreground">Mask the value in the list until someone reveals it.</span>
                        </div>
                        <button type="button" role="switch" data-slot="switch" x-data="nqSwitch(true)" x-modelable="checked" x-bind="root"
    aria-checked="true"
     data-checked                 id="nq-env-000001-secret" x-model="form.secret" class="relative inline-flex h-5 w-9 shrink-0 items-center rounded-full border border-transparent bg-nq-line-strong p-0.5 outline-none transition-colors duration-150 ease-nq data-checked: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">
    <span data-slot="switch-thumb"  data-checked         x-bind:data-checked="checked ? '' : undefined" x-bind:data-unchecked="checked ? undefined : ''"
        class="block size-4 rounded-full bg-background shadow-xs data-checked:bg-primary-foreground transition-[translate] duration-150 ease-nq data-checked:translate-x-3.5 rtl:data-checked:-translate-x-3.5"></span>
    </button>
                    </div>
                    <div data-slot="alert" data-tone="danger" role="alert"
        x-show="formError" style="display: none" 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>
                    <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-bind:disabled="formPending" x-on:click="closeEdit()" 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:disabled="formPending || (keyProblem !== null &amp;&amp; touched)" x-bind:aria-busy="formPending ? &#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 px-[var(--nq-control-pad)]">
        <svg data-slot="spinner" aria-hidden="true" style="display: none;" x-show="formPending" 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>                            Save</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="importOpen" 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)] 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 max-w-xl">
            <form data-slot="env-import-dialog" class="grid gap-4" novalidate x-on:submit.prevent="submitImport()">
                    <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">Import from .env</h2>
                        <p data-slot="dialog-description" :id="$id('nq-dialog', 'description')" class="text-body-sm text-muted-foreground">Paste the contents of a .env file or choose one. Nothing is sent until you import.</p></div>
                    <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">.env contents</label>
                        <textarea data-slot="textarea"
                x-model="importText" dir="ltr" rows="8" placeholder="API_URL=https://api.example.com
DATABASE_URL=postgres://..." autocapitalize="off" autocomplete="off" autocorrect="off" spellcheck="false" class="w-full min-w-0 rounded-control border border-input bg-card px-3 text-foreground 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] py-2 min-h-40 font-mono text-code text-start"></textarea>
</div>
                    <div>
                        <input x-ref="file" type="file" accept=".env,text/plain" class="sr-only" tabindex="-1" aria-hidden="true" x-on:change="readFile($event)" />
                        <button data-slot="button"
     type="button"                         x-on:click="$refs.file.click()" 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="M6 22a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h8a2.4 2.4 0 0 1 1.704.706l3.588 3.588A2.4 2.4 0 0 1 20 8v12a2 2 0 0 1-2 2z"/>
  <path d="M14 2v5a1 1 0 0 0 1 1h5"/>
  <path d="M12 12v6"/>
  <path d="m15 15-3-3-3 3"/>
</svg>                            Choose file</button>
                    </div>
                    <div class="grid gap-2 text-body-sm" aria-live="polite" x-show="importText.trim() !== ''" style="display: none">
                        <p class="text-foreground">
                            <span x-text="foundLabel"></span>
                            <span class="text-nq-warning-text" x-show="conflicts.length > 0" style="display: none"> · <span x-text="conflictsLabel"></span></span>
                        </p>
                        <div class="flex items-center gap-2" x-show="conflicts.length > 0" style="display: none">
                            <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-env-000001-overwrite" x-model="overwrite" 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">
    <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-env-000001-overwrite" class="text-foreground">Overwrite existing values</label>
                        </div>
                        <p class="text-caption text-muted-foreground" x-show="conflicts.length > 0 && ! overwrite" style="display: none">Existing variables are skipped unless you overwrite them.</p>
                        <p class="text-caption text-nq-warning-text" x-show="parsed.duplicates.length > 0" style="display: none" x-text="duplicatesLabel"></p>
                        <div data-slot="alert" data-tone="warning" role="alert"
        x-show="parsed.issues.length &gt; 0" style="display: none" 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-title" class="text-label text-foreground">Lines that could not be read</div>
                            <div data-slot="alert-description" class="text-body-sm text-muted-foreground"><ul class="m-0 list-disc ps-4">
                                <template x-for="issue in issues" x-bind:key="issue.id"><li x-text="issue.text"></li></template>
                            </ul></div>
            </div>
    </div>
                    </div>
                    <div data-slot="alert" data-tone="danger" role="alert"
        x-show="importError" style="display: none" 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="importError"></span></div>
            </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-bind:disabled="importPending" x-on:click="closeImport()" 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:disabled="importPending || importable.length === 0" x-bind:aria-busy="importPending ? &#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 px-[var(--nq-control-pad)]">
        <svg data-slot="spinner" aria-hidden="true" style="display: none;" x-show="importPending" 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>                            <span x-text="importLabel"></span></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="alert-dialog" x-data="nqAlertDialog(false)" x-modelable="open" x-id="['nq-alert-dialog']" x-model="deleteOpen" class="contents">
    <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"><bdi dir="ltr" class="font-mono" x-text="deleteHeading"></bdi></h2>
                    <p data-slot="alert-dialog-description" :id="$id('nq-alert-dialog', 'description')" class="text-body-sm text-muted-foreground">This removes the variable from this environment. Running deployments keep their current value until they restart.</p></div>
                <div data-slot="alert" data-tone="danger" role="alert"
        x-show="deleteError" style="display: none" 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="deleteError"></span></div>
            </div>
    </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()" x-bind:disabled="deletePending" 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="env-delete-confirm"
     type="button"                         x-bind:disabled="deletePending" x-bind:aria-busy="deletePending ? &#039;true&#039; : null" x-on:click="confirmDelete()" 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)]">
        <svg data-slot="spinner" aria-hidden="true" style="display: none;" x-show="deletePending" 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>                        Delete</button></div>
        </div>
    </div>
</template>
</div>
    </section>
</div>
```
