mildly-basic-auth 0.2.0

Basic auth with nicer UX.
Documentation
<!doctype html>
<html lang="en">
  <head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <meta name="robots" content="noindex, nofollow" />
    <title>Welcome!</title>
    <!--
      No external resources: the unauthenticated wall must not phone home
      (leaking the visitor IP and protected origin before login).
    -->
    <style>
      :root {
        --background: oklch(1 0 0);
        --foreground: oklch(0.141 0.005 285.823);
        --primary: oklch(0.21 0.006 285.885);
        --primary-foreground: oklch(0.985 0 0);
        --muted-foreground: oklch(0.552 0.016 285.938);
        --border: oklch(0.92 0.004 286.32);
        --input: oklch(0.92 0.004 286.32);
        --ring: oklch(0.705 0.015 286.067);
        --radius: 0.625rem;
      }

      @media (prefers-color-scheme: dark) {
        :root {
          --background: oklch(0.141 0.005 285.823);
          --foreground: oklch(0.985 0 0);
          --primary: oklch(0.92 0.004 286.32);
          --primary-foreground: oklch(0.21 0.006 285.885);
          --muted-foreground: oklch(0.705 0.015 286.067);
          --border: oklch(1 0 0 / 10%);
          --input: oklch(1 0 0 / 15%);
          --ring: oklch(0.552 0.016 285.938);
        }
      }

      *,
      *::before,
      *::after {
        box-sizing: border-box;
        border-color: var(--border);
      }

      html {
        min-height: 100%;
        color-scheme: light;
        -webkit-text-size-adjust: 100%;
      }

      body {
        min-height: 100svh;
        margin: 0;
        background: var(--background);
        color: var(--foreground);
        font-family: system-ui, sans-serif;
        -webkit-font-smoothing: antialiased;
        -moz-osx-font-smoothing: grayscale;
      }

      button,
      input {
        font: inherit;
      }

      button {
        border: 0;
      }

      .page {
        display: flex;
        min-height: 100svh;
        align-items: center;
        justify-content: center;
        gap: 1.5rem;
        padding: 1.5rem;
      }

      .panel {
        display: flex;
        width: 100%;
        max-width: 24rem;
        flex-direction: column;
        gap: 1.5rem;
      }

      .lock {
        width: 1.5rem;
        height: 1.5rem;
        margin: 0 auto;
        color: var(--foreground);
      }

      .form {
        display: flex;
        flex-direction: column;
        gap: 1.5rem;
      }

      .input {
        display: flex;
        width: 100%;
        min-width: 0;
        height: 2.75rem;
        border: 1px solid var(--input);
        border-radius: calc(var(--radius) - 2px);
        background: transparent;
        padding: 0.5rem 0.75rem;
        color: var(--foreground);
        font-size: 1rem;
        line-height: 1.5rem;
        outline: none;
        box-shadow: 0 1px 2px rgb(0 0 0 / 5%);
        transition:
          color 150ms ease,
          box-shadow 150ms ease,
          border-color 150ms ease;
      }

      .input::placeholder {
        color: var(--muted-foreground);
      }

      .input:focus-visible {
        border-color: var(--ring);
        box-shadow: 0 0 0 3px color-mix(in oklch, var(--ring), transparent 50%);
      }

      .button {
        display: inline-flex;
        width: 100%;
        height: 2.75rem;
        cursor: pointer;
        user-select: none;
        align-items: center;
        justify-content: center;
        gap: 0.5rem;
        border: 1px solid transparent;
        border-radius: calc(var(--radius) - 2px);
        background: var(--primary);
        color: var(--primary-foreground);
        padding: 0.5rem 1rem;
        font-size: 0.875rem;
        font-weight: 500;
        line-height: 1.25rem;
        outline: none;
        box-shadow: 0 1px 2px rgb(0 0 0 / 5%);
        -webkit-tap-highlight-color: transparent;
        transition:
          background-color 150ms ease,
          border-color 150ms ease,
          box-shadow 150ms ease,
          color 150ms ease;
      }

      .button:hover {
        background: color-mix(in oklch, var(--primary), transparent 3%);
      }

      .button:focus-visible {
        border-color: var(--ring);
        box-shadow: 0 0 0 3px color-mix(in oklch, var(--ring), transparent 50%);
      }

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

      @media (min-width: 48rem) {
        .page {
          padding: 2.5rem;
        }

        .input,
        .button {
          height: 2.25rem;
        }

        .input {
          padding-top: 0.25rem;
          padding-bottom: 0.25rem;
          font-size: 0.875rem;
          line-height: 1.25rem;
        }
      }

      @media (prefers-color-scheme: dark) {
        html {
          color-scheme: dark;
        }

        .input {
          background-color: var(--input);
        }

        @supports (color: color-mix(in lab, red, red)) {
          .input {
            background-color: color-mix(
              in oklab,
              var(--input) 30%,
              transparent
            );
          }
        }
      }
    </style>
  </head>
  <body>
    <main class="page">
      <div class="panel">
        <!-- Lock icon from Lucide (https://lucide.dev/icons/lock), ISC license. -->
        <svg
          class="lock"
          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"
          aria-hidden="true"
        >
          <rect width="18" height="11" x="3" y="11" rx="2" ry="2"></rect>
          <path d="M7 11V7a5 5 0 0 1 10 0v4"></path>
        </svg>
        <form class="form" method="post">
          <label class="sr-only" for="password">Password</label>
          <input
            class="input"
            id="password"
            type="password"
            name="password"
            placeholder="Password"
            autocomplete="current-password"
            required
          />
          <button class="button" type="submit">Enter</button>
        </form>
      </div>
    </main>
  </body>
</html>