/* ═══════════════════════════════════════════════════════════
   adminkit — Precision Noir
   A refined, dark-first admin shell inspired by Linear & Vercel.
   Uses OpenProps tokens, CSS nesting, semantic selectors.
   ═══════════════════════════════════════════════════════════ */

/* Self-hosted OpenProps design tokens — no unpkg.com request from the admin
   (a strict CSP with style-src 'self' blocks the CDN import, and self-hosting
   matches the project's supply-chain posture; same rationale as the fonts).
   Relative path resolves under the admin shell's mount prefix. */
@import "open-props.css" layer(design.tokens);
/* Self-hosted Plus Jakarta Sans + JetBrains Mono — no fonts.googleapis/gstatic
   request from the admin (GDPR / supply-chain, #111). Relative path resolves
   under whatever prefix the admin shell is mounted at ({prefix}/static/...). */
@import "fonts/admin-fonts.css";

/* ── Design Tokens ── */

:root {
  --font-sans: "Plus Jakarta Sans", system-ui, sans-serif;
  --font-mono: "JetBrains Mono", ui-monospace, monospace;

  /* Surface system — layered depth */
  --surface-0: #0c0c0f;
  --surface-1: #111114;
  --surface-2: #18181c;
  --surface-3: #1f1f24;
  --surface-4: #26262c;
  --surface-raised: #2a2a32;

  /* Text hierarchy */
  --text-1: #ececef;
  --text-2: #a1a1aa;
  --text-3: #63636e;
  --text-ghost: #3f3f47;

  /* Accent — indigo with violet undertone */
  --accent: #6366f1;
  --accent-hover: #818cf8;
  /* The primary button's fill carries white 13px text, which needs 4.5:1:
     the accent itself is 4.47:1 and its lighter hover 2.98:1, so the save a
     merchant just pressed read as disabled. The fill is the accent's hue,
     deep enough to pass, and hovering deepens it rather than washing out. */
  --button-fill: #5558e3;
  --button-fill-hover: #4f46e5;
  /* Solid badges, counts and avatars carry white text too, and white on the
     pale fills reads at 1.9-3.0:1 (success 1.9, info 2.5, danger 2.8). The
     solid of each hue is deep enough for 4.5:1 in either scheme; the accent
     solid is the button fill, so a module that re-brands the button
     re-brands these with it. */
  --accent-solid: var(--button-fill);
  --success-solid: #047857;
  --danger-solid: #dc2626;
  --danger-solid-hover: #b91c1c;
  --info-solid: #1d4ed8;
  --accent-soft: rgba(99, 102, 241, 0.12);
  --accent-glow: rgba(99, 102, 241, 0.25);
  /* The accent and the semantic colours below are fills: bright enough for
     a dot, a bar or a tint on a dark surface. Written as text they must hold
     4.5:1 on their own tint over every surface, so text reads the -text
     token of the same hue, which the light scheme deepens to a 700–800
     shade. contrast_test.go measures every pair in both schemes. */
  --accent-text: #a5b4fc;
  --accent-text-hover: #c7d2fe;
  --link: var(--accent-text);
  --link-hover: var(--accent-text-hover);

  /* Semantic */
  --success: #34d399;
  --success-soft: rgba(52, 211, 153, 0.12);
  --success-text: var(--success);
  --warning: #fbbf24;
  --warning-soft: rgba(251, 191, 36, 0.12);
  --warning-text: var(--warning);
  --danger: #f87171;
  --danger-soft: rgba(248, 113, 113, 0.12);
  --danger-text: var(--danger);
  --info: #60a5fa;
  --info-soft: rgba(96, 165, 250, 0.12);
  --info-text: var(--info);

  /* Borders */
  --border: rgba(255, 255, 255, 0.06);
  --border-hover: rgba(255, 255, 255, 0.1);
  --border-focus: var(--accent);

  /* Layout */
  --nav-width: 252px;
  --panel-width: 380px;
  --header-height: 52px;
  --radius-sm: 6px;
  --radius: 8px;
  --radius-lg: 12px;

  /* Motion — snappy, not sluggish */
  --ease-out: cubic-bezier(0.16, 1, 0.3, 1);
  --duration-fast: 120ms;
  --duration: 200ms;
  --duration-slow: 350ms;
}

/* ── Reset ── */

*,
*::before,
*::after {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
}

body {
  font-family: var(--font-sans);
  background: var(--surface-0);
  color: var(--text-1);
  line-height: 1.55;
  font-size: 14px;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-rendering: optimizeLegibility;
}

::selection {
  background: var(--accent-soft);
  color: var(--accent-text-hover);
}

/* A link the page did not style otherwise wore the browser's #0000ee, a
   third blue beside the accent and unreadable on the dark scheme. :where()
   keeps both rules at zero specificity, so a link styled as a button, a nav
   item or a card keeps its own colour, hover included. */
:where(a) {
  color: var(--link);
}

:where(a:hover) {
  color: var(--link-hover);
}

/* ── Buttons ── */

button,
body[data-page="login"] > main > article[aria-labelledby="access-denied-heading"] > a {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  padding: 7px 14px;
  border: 1px solid transparent;
  border-radius: var(--radius-sm);
  font-family: var(--font-sans);
  font-size: 13px;
  font-weight: 550;
  cursor: pointer;
  background: var(--button-fill, var(--accent));
  color: var(--on-accent, white);
  box-shadow: var(--shadow-button, 0 1px 2px rgba(0, 0, 0, 0.3), inset 0 1px 0 rgba(255, 255, 255, 0.1));
  transition:
    background var(--duration-fast) var(--ease-out),
    border-color var(--duration-fast) var(--ease-out),
    transform var(--duration-fast) var(--ease-out),
    box-shadow var(--duration-fast) var(--ease-out);
  white-space: nowrap;
  user-select: none;

  /* Only where a pointer can hover: a phone keeps :hover on the button it
     just tapped, so a hover colour there is how the button stays looking. */
  @media (hover: hover) {
    &:hover {
      background: var(--button-fill-hover, var(--accent-hover));
      box-shadow: var(--shadow-button-hover, 0 2px 8px var(--accent-glow), inset 0 1px 0 rgba(255, 255, 255, 0.15));
    }
  }

  &:active {
    transform: scale(0.97);
  }

  &.secondary {
    background: var(--surface-3);
    border-color: var(--border);
    color: var(--text-1);
    box-shadow: none;

    &:hover {
      background: var(--surface-4);
      border-color: var(--border-hover);
    }
  }

  /* A size, never a look: a compact button keeps the default fill or its
     variant's (secondary, danger, ghost). When .small also stripped the fill
     and greyed the label, every compact action read as a disabled word. */
  &.small {
    padding: 5px 12px;
    font-size: 12px;
  }

  &.ghost {
    background: transparent;
    border-color: transparent;
    color: var(--text-2);
    box-shadow: none;

    &:hover {
      background: var(--surface-3);
      color: var(--text-1);
    }
  }

  &.danger {
    background: var(--danger-solid);
    border-color: transparent;
    color: var(--on-accent, white);

    &:hover {
      background: var(--danger-solid-hover);
    }
  }

  &.ghost.danger {
    background: transparent;
    border-color: transparent;
    color: var(--danger-text);
    box-shadow: none;

    &:hover {
      background: var(--danger-soft);
      color: var(--danger-text);
      filter: none;
    }
  }

  & svg {
    width: 15px;
    height: 15px;
    flex-shrink: 0;
  }
}

/* ── Inputs ── */

input,
select,
textarea {
  width: 100%;
  padding: 8px 12px;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  font-family: var(--font-sans);
  font-size: 13px;
  background: var(--surface-1);
  color: var(--text-1);
  transition:
    border-color var(--duration-fast) var(--ease-out),
    box-shadow var(--duration-fast) var(--ease-out);

  &::placeholder {
    color: var(--text-ghost);
  }

  &:focus {
    outline: none;
    border-color: var(--accent);
    box-shadow: 0 0 0 3px var(--accent-soft);
  }
}

input[type="search"] {
  &::-webkit-search-cancel-button {
    -webkit-appearance: none;
  }
}

input[type="checkbox"][role="switch"] {
  width: 32px;
  height: 18px;
  appearance: none;
  background: var(--surface-4);
  border-radius: 9px;
  position: relative;
  cursor: pointer;
  border: 1px solid var(--border);
  padding: 0;
  transition: background var(--duration) var(--ease-out);

  &::after {
    content: "";
    position: absolute;
    top: 2px;
    left: 2px;
    width: 12px;
    height: 12px;
    background: var(--text-3);
    border-radius: 50%;
    transition: transform var(--duration) var(--ease-out), background var(--duration) var(--ease-out);
  }

  &:checked {
    background: var(--accent);
    border-color: var(--accent);

    &::after {
      transform: translateX(14px);
      background: var(--on-accent, white);
    }
  }
}

/* A switch that is a link: an option whose flip loads the same page with
   that option changed (no signal, no form). The track and knob match the
   checkbox switch above, token for token; they cannot share its rule because
   the link draws them as ::before, and a pseudo-element cannot sit in the
   selector list that nesting turns into :is(). */
a[role="switch"] {
  display: grid;
  grid-template-columns: 32px minmax(0, 1fr);
  column-gap: 14px;
  align-items: start;
  color: var(--text-1);
  text-decoration: none;

  &::before {
    content: "";
    grid-row: 1 / span 2;
    width: 32px;
    height: 18px;
    margin-top: 1px;
    border-radius: 9px;
    border: 1px solid var(--border);
    background:
      radial-gradient(circle at 8px 50%, var(--text-3) 0 6px, transparent 6.5px),
      var(--surface-4);
    transition: background var(--duration) var(--ease-out);
  }
  &[aria-checked="true"]::before {
    border-color: var(--accent);
    background:
      radial-gradient(circle at 22px 50%, var(--on-accent, white) 0 6px, transparent 6.5px),
      var(--accent);
  }
  & > span { font-size: 14px; font-weight: 550; }
  & > small { font-size: 12.5px; color: var(--text-2); line-height: 1.45; }
  &:focus-visible { outline: 2px solid var(--accent); outline-offset: 4px; border-radius: 4px; }
}

/* ── Labels ── */

label {
  display: block;
  margin-bottom: 16px;

  & > span {
    display: block;
    font-size: 12px;
    font-weight: 600;
    color: var(--text-2);
    margin-bottom: 6px;
    letter-spacing: 0.01em;
  }

  &:has(input[role="switch"]) {
    display: flex;
    align-items: center;
    gap: 10px;
    cursor: pointer;

    & > span {
      margin-bottom: 0;
      font-size: 13px;
      font-weight: 500;
    }
  }

  & .required {
    color: var(--danger-text);
    font-weight: 400;
    font-size: inherit;
    background: none;
    padding: 0;
    margin-left: 1px;
  }

  & .field-error {
    display: block;
    font-size: 12px;
    color: var(--danger-text);
    margin-top: 4px;
  }

  & .field-hint {
    display: block;
    font-size: 12px;
    color: var(--text-2);
    margin-top: 4px;
  }

  &.has-error > input,
  &.has-error > textarea,
  &.has-error > select {
    border-color: var(--danger);
  }
}

/* ── Badge (mark) ── */

mark {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  padding: 2px 9px;
  border-radius: 20px;
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.02em;
  background: var(--surface-3);
  color: var(--text-2);

  &::before {
    content: "";
    width: 6px;
    height: 6px;
    border-radius: 50%;
    background: currentColor;
  }

  &[data-variant="success"] {
    background: var(--success-soft);
    color: var(--success-text);
  }

  &[data-variant="warning"] {
    background: var(--warning-soft);
    color: var(--warning-text);
  }

  &[data-variant="danger"] {
    background: var(--danger-soft);
    color: var(--danger-text);
  }

  &[data-variant="info"] {
    background: var(--info-soft);
    color: var(--info-text);
  }
}

/* ── Description List ── */

dl {
  & dt {
    font-size: 11px;
    font-weight: 600;
    color: var(--text-3);
    text-transform: uppercase;
    letter-spacing: 0.05em;
    margin-top: 16px;

    &:first-of-type {
      margin-top: 0;
    }
  }

  & dd {
    padding: 6px 0 0;
    font-size: 14px;
    color: var(--text-1);
  }
}

/* ═══════════════════════════════════════
   Admin Shell
   ═══════════════════════════════════════ */

[data-admin] {
  display: grid;
  grid-template-columns: var(--nav-width) 1fr;
  grid-template-rows: var(--header-height) 1fr;
  grid-template-areas:
    "nav header"
    "nav content";
  min-height: 100vh;
  background: var(--surface-0);

  /* ── Left Sidebar ── */
  & > #admin-nav {
    grid-area: nav;
    background: var(--surface-1);
    border-right: 1px solid var(--border);
    display: flex;
    flex-direction: column;
    overflow-y: auto;
    overflow-x: hidden;

    /* Scrollbar */
    &::-webkit-scrollbar { width: 4px; }
    &::-webkit-scrollbar-thumb {
      background: var(--surface-4);
      border-radius: 4px;
    }

    & [role="banner"] {
      padding: 16px 18px;
      font-size: 14px;
      font-weight: 700;
      color: var(--text-1);
      letter-spacing: -0.01em;
      display: flex;
      align-items: center;
      gap: 10px;
      border-bottom: 1px solid var(--border);
      min-height: var(--header-height);

      & strong {
        font-weight: 700;
      }

      /* Lifted from the brand link's former inline style — same declarations,
         now themeable. */
      & .brand-link {
        text-decoration: none;
        color: inherit;
        display: flex;
        align-items: center;
        gap: var(--size-2);
      }

      & .brand-logo {
        border-radius: 4px;
      }
    }

    & [role="menubar"] {
      list-style: none;
      flex: 1;
      padding: 8px;

      & [role="separator"] {
        padding: 20px 10px 6px;
        font-size: 10px;
        font-weight: 700;
        text-transform: uppercase;
        letter-spacing: 0.08em;
        color: var(--text-ghost);
        user-select: none;
      }

      & [role="none"] {
        margin: 1px 0;
      }

      & [role="menuitem"] {
        display: flex;
        align-items: center;
        gap: 9px;
        padding: 7px 10px;
        cursor: pointer;
        border-radius: var(--radius-sm);
        text-decoration: none;
        color: var(--text-2);
        font-size: 13px;
        font-weight: 500;
        transition:
          background var(--duration-fast) var(--ease-out),
          color var(--duration-fast) var(--ease-out);
        position: relative;

        &:hover {
          background: var(--surface-3);
          color: var(--text-1);
        }

        &[aria-current="page"] {
          background: var(--accent-soft);
          color: var(--accent-text);

          &::before {
            content: "";
            position: absolute;
            left: 0;
            top: 50%;
            transform: translateY(-50%);
            width: 2px;
            height: 16px;
            background: var(--accent-text);
            border-radius: 2px;
          }
        }

        & [aria-hidden] {
          width: 18px;
          height: 18px;
          display: flex;
          align-items: center;
          justify-content: center;
          font-size: 14px;
          opacity: 0.7;
          flex-shrink: 0;
        }

        & svg {
          width: 16px;
          height: 16px;
          opacity: 0.5;
          flex-shrink: 0;
        }
      }

      /* Collapsible nav groups */
      & .nav-group {
        & > [role="menuitem"] {
          justify-content: space-between;
          background: transparent;
          border: none;
          box-shadow: none;
          width: 100%;
          font-family: var(--font-sans);
          min-height: auto;

          & .nav-chevron {
            width: 14px;
            height: 14px;
            opacity: 0.3;
            margin-left: auto;
            flex-shrink: 0;
            transition: transform var(--duration-fast) var(--ease-out);
          }

          &[aria-expanded="true"] .nav-chevron {
            transform: rotate(90deg);
            opacity: 0.5;
          }
        }

        & [role="group"] {
          list-style: none;
          padding: 0 0 2px 27px;
          margin: 0;

          & [role="menuitem"] {
            font-size: 12.5px;
            padding: 5px 10px;
            color: var(--text-3);

            & svg {
              width: 14px;
              height: 14px;
            }
          }
        }
      }
    }

    /* Lifted from the account links' former inline styles — same
       declarations, now themeable. The extra (app-supplied) links carry the
       additional vertical padding the inline version had. */
    & > footer .account-link {
      display: flex;
      align-items: center;
      gap: 8px;
      text-decoration: none;
      color: inherit;
    }

    & > footer .account-link-extra {
      padding: var(--size-1) 0;
    }

    & > footer {
      padding: 12px 18px;
      border-top: 1px solid var(--border);
      font-size: 12px;
      color: var(--text-3);
      display: flex;
      align-items: center;
      gap: 8px;

      & > span {
        font-weight: 500;
      }
    }
  }

  /* ── Header ── */
  & > header {
    grid-area: header;
    background: var(--surface-1);
    border-bottom: 1px solid var(--border);
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 0 24px;
    min-height: var(--header-height);

    & h1 {
      font-size: 14px;
      font-weight: 600;
      color: var(--text-1);
      letter-spacing: -0.01em;
    }

    & > span {
      display: flex;
      align-items: center;
      gap: 8px;
      font-size: 12px;
      color: var(--text-3);
      font-weight: 500;
    }
  }

  /* ── Page wrapper (holds data-init SSE connection) ── */
  & > #admin-page {
    display: contents;
  }

  /* ── Main Content ── */
  & > #admin-page > main,
  & > main {
    grid-area: content;
    padding: 28px 32px;
    overflow-y: auto;
    background: var(--surface-0);

    /* Scrollbar */
    &::-webkit-scrollbar { width: 6px; }
    &::-webkit-scrollbar-thumb {
      background: var(--surface-4);
      border-radius: 6px;
    }

    & > section {
      max-width: 1100px;
    }
  }

  /* ── Toast Container ── */
  & > [role="status"] {
    position: fixed;
    top: 12px;
    right: 12px;
    z-index: 9000;
    display: flex;
    flex-direction: column;
    gap: 6px;
    pointer-events: none;
    max-width: 360px;

    & [role="alert"] {
      pointer-events: auto;
      display: flex;
      align-items: center;
      gap: 10px;
      padding: 10px 14px;
      border-radius: var(--radius);
      background: var(--surface-3);
      border: 1px solid var(--border);
      box-shadow: var(--shadow-toast,
        0 8px 24px rgba(0, 0, 0, 0.4),
        0 2px 8px rgba(0, 0, 0, 0.2));
      font-size: 13px;
      font-weight: 500;
      color: var(--text-1);
      backdrop-filter: blur(12px);
      animation: toast-enter var(--duration-slow) var(--ease-out);

      /* Severity reads as a dot + a faint wash of the severity hue over the
         surface — the same grammar as the status badges — never a side
         stripe. The wash tints the border too, so the edge agrees with the
         dot without shouting. */
      &::before {
        content: "";
        flex: none;
        width: 7px;
        height: 7px;
        border-radius: 50%;
        background: var(--text-3);
      }

      &[data-level="success"] {
        background: color-mix(in oklab, var(--success) 10%, var(--surface-3));
        border-color: color-mix(in oklab, var(--success) 30%, var(--border));
        &::before { background: var(--success); }
      }

      /* Both names are in use for a failure; one left out paints its toast
         as neutral as a note. */
      &[data-level="error"],
      &[data-level="danger"] {
        background: color-mix(in oklab, var(--danger) 10%, var(--surface-3));
        border-color: color-mix(in oklab, var(--danger) 30%, var(--border));
        &::before { background: var(--danger); }
      }

      &[data-level="warning"] {
        background: color-mix(in oklab, var(--warning) 10%, var(--surface-3));
        border-color: color-mix(in oklab, var(--warning) 30%, var(--border));
        &::before { background: var(--warning); }
      }

      &[data-level="info"] {
        background: color-mix(in oklab, var(--accent) 10%, var(--surface-3));
        border-color: color-mix(in oklab, var(--accent) 30%, var(--border));
        &::before { background: var(--accent); }
      }

      & span {
        flex: 1;
      }

      /* The dismiss ✕ — quiet until hovered; the toast is the message, the
         close is furniture. */
      & > button {
        flex: none;
        padding: 2px 4px;
        background: transparent;
        border: none;
        box-shadow: none;
        color: var(--text-3);
        font-size: 12px;
        line-height: 1;
        cursor: pointer;

        &:hover {
          color: var(--text-1);
          background: transparent;
        }
      }
    }
  }
}

/* ── Page Header (hgroup) ── */

hgroup {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 20px;
  gap: 16px;

  & h1 {
    font-size: 20px;
    font-weight: 700;
    color: var(--text-1);
    letter-spacing: -0.02em;
  }

  & nav {
    display: flex;
    gap: 8px;
  }
}

/* ── Statistics Grid ── */

[role="grid"][aria-label] {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
  gap: 12px;

  & > article {
    background: var(--surface-2);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    padding: 18px 20px;
    transition: border-color var(--duration) var(--ease-out);

    &:hover {
      border-color: var(--border-hover);
    }

    & data {
      display: block;
      font-size: 28px;
      font-weight: 700;
      color: var(--text-1);
      letter-spacing: -0.03em;
      font-variant-numeric: tabular-nums;
      font-family: var(--font-sans);
    }

    & p {
      font-size: 12px;
      color: var(--text-3);
      margin-top: 4px;
      font-weight: 500;
      text-transform: uppercase;
      letter-spacing: 0.04em;
    }

    & small {
      display: block;
      font-size: 11px;
      font-weight: 600;
      margin-top: 6px;
      color: var(--text-3);

      &[data-variant="success"] { color: var(--success-text); }
      &[data-variant="warning"] { color: var(--warning-text); }
      &[data-variant="danger"] { color: var(--danger-text); }
    }
  }
}

/* ── Table ── */

table {
  width: 100%;
  border-collapse: collapse;
  background: var(--surface-1);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  overflow: hidden;
  font-variant-numeric: tabular-nums;

  & th {
    text-align: left;
    padding: 10px 16px;
    font-size: 11px;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    color: var(--text-3);
    border-bottom: 1px solid var(--border);
    background: var(--surface-2);
    white-space: nowrap;
    user-select: none;
  }

  & td {
    padding: 11px 16px;
    border-bottom: 1px solid var(--border);
    font-size: 13px;
    color: var(--text-2);
  }

  & tr:last-child td {
    border-bottom: none;
  }

  /* A row a support operator wrote while signed in as the owner. The badge
     names it; the tint lets the merchant find such rows while scrolling. */
  & tr[data-impersonated] td {
    background: var(--warning-soft);
  }

  & td a {
    color: var(--text-1);
    text-decoration: none;
    font-weight: 500;

    &:hover {
      color: var(--link-hover);
      text-decoration: underline;
    }
  }
}

/* ── Empty State ── */

section[role="status"] {
  text-align: center;
  padding: 56px 24px;
  color: var(--text-3);
  background: var(--surface-1);
  border: 1px dashed var(--border);
  border-radius: var(--radius);
  font-size: 14px;

  & p {
    max-width: 300px;
    margin: 0 auto 16px;
    line-height: 1.6;
  }
}

/* ── Panel (right sidebar) ── */

aside[aria-label] {
  position: fixed;
  top: 0;
  right: 0;
  bottom: 0;
  width: var(--panel-width);
  background: var(--surface-1);
  border-left: 1px solid var(--border);
  z-index: 7000;
  display: flex;
  flex-direction: column;
  box-shadow: var(--shadow-panel,
    -8px 0 24px rgba(0, 0, 0, 0.3),
    -2px 0 8px rgba(0, 0, 0, 0.15));
  animation: panel-enter var(--duration-slow) var(--ease-out);

  & > header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 14px 20px;
    border-bottom: 1px solid var(--border);
    min-height: var(--header-height);

    & h3 {
      font-size: 14px;
      font-weight: 650;
      color: var(--text-1);
    }
  }

  & > div {
    padding: 20px;
    overflow-y: auto;
    flex: 1;

    &::-webkit-scrollbar { width: 4px; }
    &::-webkit-scrollbar-thumb {
      background: var(--surface-4);
      border-radius: 4px;
    }
  }
}

/* ── Dialog (modal) ── */

dialog[open] {
  position: fixed;
  inset: 0;
  width: 100%;
  height: 100%;
  background: var(--backdrop-dialog, rgba(0, 0, 0, 0.6));
  backdrop-filter: blur(4px);
  border: none;
  z-index: 8000;
  display: flex;
  align-items: center;
  justify-content: center;
  animation: backdrop-enter var(--duration) var(--ease-out);

  & > article {
    background: var(--surface-2);
    border: 1px solid var(--border);
    border-radius: var(--radius-lg);
    width: 90%;
    max-width: 480px;
    max-height: calc(100vh - 48px);
    display: flex;
    flex-direction: column;
    overflow: hidden;
    box-shadow: var(--shadow-dialog,
      0 16px 48px rgba(0, 0, 0, 0.5),
      0 4px 16px rgba(0, 0, 0, 0.3));
    animation: modal-enter var(--duration-slow) var(--ease-out);

    & > header {
      display: flex;
      align-items: center;
      justify-content: space-between;
      padding: 16px 20px;
      border-bottom: 1px solid var(--border);
      flex-shrink: 0;

      & h3 {
        font-size: 15px;
        font-weight: 650;
        color: var(--text-1);
      }
    }

    & > div {
      padding: 20px;
      color: var(--text-2);
      font-size: 14px;
      line-height: 1.6;
      overflow-y: auto;
      flex: 1;
    }

    & > footer {
      display: flex;
      gap: 8px;
      justify-content: flex-end;
      padding: 14px 20px;
      border-top: 1px solid var(--border);
      flex-shrink: 0;
    }
  }
}

dialog[open] fieldset {
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  padding: 12px 16px;
  margin: 0;

  & legend {
    font-size: 13px;
    font-weight: 500;
    color: var(--text-2);
    padding: 0 4px;
  }

  & label {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 4px 0;
    flex-direction: row;

    /* Plain checkboxes only: a switch keeps the shared switch size above,
       otherwise this more specific rule squashes it into a 16px square. */
    & input[type="checkbox"]:not([role="switch"]) {
      width: 16px;
      height: 16px;
      margin: 0;
    }

    & span {
      font-size: 13px;
      color: var(--text-1);
    }
  }
}

/* ── Search ── */

search {
  display: block;
  margin-bottom: 16px;
  position: relative;

  & input {
    padding-left: 36px;
    background: var(--surface-2);
  }

  &::before {
    content: "";
    position: absolute;
    left: 12px;
    top: 50%;
    transform: translateY(-50%);
    width: 14px;
    height: 14px;
    background: var(--text-ghost);
    mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2.5' stroke-linecap='round'%3E%3Ccircle cx='11' cy='11' r='8'/%3E%3Cline x1='21' y1='21' x2='16.65' y2='16.65'/%3E%3C/svg%3E") center / contain no-repeat;
    -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2.5' stroke-linecap='round'%3E%3Ccircle cx='11' cy='11' r='8'/%3E%3Cline x1='21' y1='21' x2='16.65' y2='16.65'/%3E%3C/svg%3E") center / contain no-repeat;
    pointer-events: none;
    z-index: 1;
  }
}

/* ═══════════════════════════════════════
   Login Page
   ═══════════════════════════════════════ */

body[data-page="login"] {
  background: var(--surface-0);
  min-height: 100vh;

  /* Subtle radial glow behind the card */
  &::before {
    content: "";
    position: fixed;
    top: 30%;
    left: 50%;
    transform: translate(-50%, -50%);
    width: 600px;
    height: 400px;
    background: radial-gradient(ellipse, var(--accent-soft), transparent 70%);
    pointer-events: none;
    z-index: 0;
  }

  & > main {
    min-height: 100vh;
    display: flex;
    align-items: center;
    justify-content: center;
    padding-inline: 16px;
    position: relative;
    z-index: 1;

    & > article {
      background: var(--surface-1);
      border: 1px solid var(--border);
      border-radius: var(--radius-lg);
      padding: 36px;
      width: 100%;
      max-width: 380px;
      box-shadow: var(--shadow-login-card,
        0 8px 32px rgba(0, 0, 0, 0.3),
        0 2px 8px rgba(0, 0, 0, 0.2));

      & h1 {
        font-size: 18px;
        font-weight: 700;
        margin-bottom: 24px;
        text-align: center;
        color: var(--text-1);
        letter-spacing: -0.02em;
      }

      & p {
        text-align: center;
        color: var(--text-3);
        margin-bottom: 20px;
        font-size: 13px;
        line-height: 1.5;

        & strong {
          color: var(--text-1);
          font-weight: 600;
        }
      }

      & [role="alert"] {
        color: var(--danger-text);
        font-size: 13px;
        text-align: center;
        margin-bottom: 12px;
        font-weight: 500;
      }

      & button {
        width: 100%;
        padding: 9px 16px;
        margin-top: 4px;
      }
    }
  }
}

/* The language switcher and the "or" divider on the login steps. They used to
   ride in an inline <style> in the login template, but a login step arrives as
   a morph, and a <style> in a morph carries the response's nonce, which the
   page refuses. A stylesheet has no nonce to get wrong. */
body[data-page="login"] {
  & > .locale-switcher {
    position: fixed;
    top: 16px;
    right: 20px;
    display: flex;
    gap: 8px;
    align-items: center;
    z-index: 10;

    /* Each language is a button, so it carries a button's chrome and none of
       it is wanted here: what should show is the word and which one is on. */
    & button {
      font: inherit;
      font-size: 12px;
      color: var(--text-2);
      background: none;
      border: 0;
      cursor: pointer;
      text-decoration: none;
      padding: 4px 6px;
      border-radius: 4px;

      &:hover {
        color: var(--text-1);
        background: var(--surface-3);
      }
      &[aria-current="true"] {
        color: var(--text-1);
        font-weight: 600;
        background: var(--surface-3);
      }
    }
    & .locale-sep {
      color: var(--text-3);
      font-size: 10px;
      user-select: none;
    }
  }

  /* The label sits between two rules that flex to fill the sides, so no line
     is ever painted across the text, whatever the card colour or paint order. */
  & .or-sep {
    display: flex;
    align-items: center;
    gap: 12px;
    margin: 20px 0;
    color: var(--text-3);
    font-size: 12px;

    &::before,
    &::after {
      content: "";
      flex: 1 1 0;
      height: 1px;
      background: var(--border);
    }
    & > span {
      flex: 0 0 auto;
    }
  }
}

/* ═══════════════════════════════════════
   User Avatar
   ═══════════════════════════════════════ */

.user-avatar {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 28px;
  height: 28px;
  border-radius: 50%;
  background: var(--accent-solid);
  color: var(--on-accent, white);
  font-size: 12px;
  font-weight: 700;
  flex-shrink: 0;
  letter-spacing: 0.02em;
  text-transform: uppercase;
}

/* ═══════════════════════════════════════
   Mobile Navigation
   ═══════════════════════════════════════ */

.mobile-nav-toggle {
  display: none;
}

.mobile-nav-close {
  display: none;
}

/* ═══════════════════════════════════════
   Section Heading (dashboard)
   ═══════════════════════════════════════ */

.section-heading {
  font-size: 14px;
  font-weight: 650;
  color: var(--text-2);
  margin: 24px 0 12px;
  letter-spacing: -0.01em;
}

/* ═══════════════════════════════════════
   Contextual element styles
   ═══════════════════════════════════════ */

/* Buttons in panels fill width */
aside[aria-label] button:not(.small) {
  width: 100%;
  margin-bottom: 8px;
}

/* Dividers in panels */
aside[aria-label] hr {
  border: none;
  border-top: 1px solid var(--border);
  margin: 16px 0;
}

/* Monospace code in table cells and definition lists */
td code,
dd code {
  font-family: var(--font-mono);
  font-size: 12px;
}

code.muted {
  color: var(--text-3);
}

/* Empty table row placeholder */
.empty-row {
  text-align: center;
  padding: 32px !important;
  color: var(--text-3);
}

/* Muted text (used for counts, etc.) */
.muted {
  color: var(--text-3);
}

/* Standalone muted paragraph (for counts below tables, etc.) */
p.muted {
  font-size: 12px;
  margin-top: 12px;
}

/* Panel subheading */
.panel-subheading {
  font-size: 13px;
  font-weight: 600;
  color: var(--text-2);
  margin-bottom: 8px;
}

/* Assignment list (role users, etc.) */
.assignment-list {
  list-style: none;
  padding: 0;
  margin: 0;

  & > li {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 6px 0;
    border-bottom: 1px solid var(--border);
  }
}

/* ═══════════════════════════════════════
   Monospace Input
   ═══════════════════════════════════════ */

.mono-input {
  font-family: var(--font-mono);
  font-size: 12px;
}

/* ═══════════════════════════════════════
   Panel / Block Components
   ═══════════════════════════════════════ */

.panel-section-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 12px;
}

.inline-select {
  width: auto;
  padding: 4px 8px;
  font-size: 12px;
}

.empty-hint {
  text-align: center;
  padding: 20px;
  color: var(--text-3);
  font-size: 13px;
}

.block-card {
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  padding: 12px;
  margin-bottom: 8px;
}

.block-card-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 8px;
}

.block-type-label {
  font-size: 11px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--text-3);
}

.block-card-body {
  font-size: 13px;
  color: var(--text-2);
  word-break: break-word;
}

.block-card-label {
  font-weight: 600;
  font-size: 13px;
}

.block-card-url {
  margin-left: 8px;
  font-size: 11px;
}

/* Menu editor: items nested as the storefront draws them; each row's actions
   wrap under its label on a phone, and an edit row stacks its fields. */
.menu-tree {
  list-style: none;
  margin: 0;
  padding: 0;

  & ol {
    list-style: none;
    margin: 0;
    padding-inline-start: 20px;
    border-inline-start: 2px solid var(--border);
  }

  & li > .block-card {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: 8px;

    & > label,
    & > .edit-actions {
      flex: 1 1 100%;
    }
  }

  & [role="group"] {
    display: flex;
    flex-wrap: wrap;
    gap: 4px;
  }
}

.menu-danger {
  margin-top: 32px;
  padding: 12px 16px;
  border: 1px solid var(--danger);
  border-radius: var(--radius-sm);
}

.word-break {
  word-break: break-all;
}

/* ═══════════════════════════════════════
   Media Grid
   ═══════════════════════════════════════ */

.media-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(160px, 1fr));
  gap: 12px;
  list-style: none;
  padding: 0;
  margin: 0;
}

.media-card {
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 12px;
  cursor: pointer;
  transition: border-color var(--duration-fast) var(--ease-out);

  &:hover {
    border-color: var(--border-hover);
  }
}

.media-thumb {
  width: 100%;
  aspect-ratio: 1;
  object-fit: cover;
  border-radius: 4px;
}

.media-thumb-placeholder {
  width: 100%;
  aspect-ratio: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--surface-3);
  border-radius: 4px;
  font-size: 32px;
  color: var(--text-3);
}

.media-filename {
  margin: 8px 0 2px;
  font-size: 13px;
  font-weight: 500;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.media-preview {
  width: 100%;
  border-radius: var(--radius);
  margin-bottom: 16px;
}

.media-preview-placeholder {
  width: 100%;
  aspect-ratio: 16/9;
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--surface-2);
  border-radius: var(--radius);
  margin-bottom: 16px;
  font-size: 48px;
  color: var(--text-3);
}

/* ═══════════════════════════════════════
   API Tokens (My Account: token list + create-token picker)
   ═══════════════════════════════════════ */

/* Presets: one-click scope choices above the permission list. */
dialog.token-picker [role="group"] {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin: 8px 0 12px;
}

/* A token's scopes wrap inside a bounded cell: a full-access token names every
   permission, which on one nowrap line would stretch the table off screen. */
.token-scopes {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 4px;
  max-width: 36ch;
  margin: 0;
  padding: 0;
  list-style: none;
  white-space: normal;

  & li:not(:last-child)::after {
    content: ",";
  }

  & li,
  & code,
  & small {
    font-size: 11px;
    color: var(--text-3);
  }
}

/* ═══════════════════════════════════════
   Media Picker (choose-an-image dialog)
   ═══════════════════════════════════════ */

dialog.media-picker {
  & > article {
    width: min(760px, 92vw);
    max-height: 86vh;
    display: flex;
    flex-direction: column;
  }

  /* Only the grid scrolls. A long grid (the library and the store's product
     photos) otherwise squeezes the rows above it, and on a phone the upload
     row slid under the header, which then took its taps. */
  & > article > :not(.media-picker-grid-wrap) {
    flex-shrink: 0;
  }

  & .media-picker-upload {
    display: flex;
    gap: 8px;
    align-items: end;
    padding: 12px 16px;
    background: var(--surface-2);
    border: 1px dashed var(--border);
    border-radius: var(--radius);
    margin-bottom: 12px;

    & > .upload-label {
      flex: 1;
      margin: 0;
    }
  }

  & .media-picker-grid-wrap {
    overflow-y: auto;
    flex: 1;
    min-height: 120px;
  }

  /* Image fields show a square thumbnail, not a filename caption list. */
  & .media-grid {
    grid-template-columns: repeat(auto-fill, minmax(120px, 1fr));
  }
}

/* Inline image field: preview thumbnail + choose/remove actions. */
.media-field {
  display: flex;
  flex-direction: column;
  gap: 8px;

  & > .media-field-preview {
    width: 140px;
    height: 140px;
    object-fit: cover;
    border-radius: var(--radius);
    border: 1px solid var(--border);
    background: var(--surface-2);
  }

  & > .media-field-actions {
    display: flex;
    gap: 8px;
  }
}

/* ═══════════════════════════════════════
   Font Picker (choose-a-font dialog)
   ═══════════════════════════════════════ */

dialog.font-picker {
  & > article {
    width: min(680px, 94vw);
    max-height: 88vh;
    display: flex;
    flex-direction: column;
    padding: 0;
    overflow: hidden;
  }

  & > article > header {
    padding: 20px 22px 14px;
    align-items: flex-start;

    & h3 {
      margin: 0;
    }

    & p {
      margin: 2px 0 0;
      font-size: 13px;
      color: var(--text-3);
    }
  }

  /* The admin's `search` rule draws the magnifier at the element's left
     edge and pads the input around it, so the bar is spaced by margin: a
     padding here would move the element's edge, and the icon with it, out
     past the input's. */
  & .font-search {
    margin: 0 22px 14px;
    padding: 0;

    & > input {
      width: 100%;
    }
  }

  & .font-list {
    list-style: none;
    margin: 0;
    padding: 0 22px 22px;
    overflow-y: auto;
    flex: 1;
    display: flex;
    flex-direction: column;
    gap: 10px;
  }

  /* A button centres its content on one line; a card stretches its rows to
     its width and lets the sample wrap, or a phone shows a sample wider than
     the card. */
  & .font-option {
    width: 100%;
    text-align: left;
    display: flex;
    flex-direction: column;
    align-items: stretch;
    white-space: normal;
    gap: 10px;
    padding: 16px 18px;
    background: var(--surface-1);
    border: 1px solid var(--border);
    border-radius: 12px;
    cursor: pointer;
    transition: border-color var(--duration-fast) var(--ease-out),
      background var(--duration-fast) var(--ease-out),
      transform var(--duration-fast) var(--ease-out);

    &:hover {
      border-color: var(--border-hover);
      background: var(--surface-2);
      transform: translateY(-1px);
    }

    &.active {
      border-color: var(--accent);
      box-shadow: 0 0 0 1px var(--accent) inset;
    }
  }

  & .font-option-head {
    display: flex;
    align-items: center;
    gap: 10px;
  }

  & .font-option-name {
    font-size: 13px;
    font-weight: 600;
    color: var(--text-1);
    letter-spacing: -0.01em;
  }

  & .font-option-cat {
    font-size: 10px;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    color: var(--text-3);
    background: var(--surface-3);
    padding: 2px 7px;
    border-radius: 999px;
  }

  /* The check sits at the right and only shows for the active font. */
  & .font-option-check {
    margin-left: auto;
    display: inline-flex;
    color: var(--accent-text);
    opacity: 0;
    transition: opacity var(--duration-fast) var(--ease-out);
  }

  & .font-option.active .font-option-check {
    opacity: 1;
  }

  /* The sample, drawn in the font itself: each sample's family comes from
     its class in the ecommerce admin's fonts/samples.css. */
  & .font-option-preview {
    font-size: 28px;
    line-height: 1.25;
    overflow-wrap: anywhere;
    color: var(--text-1);
    /* Avoid layout shift while the web font swaps in. */
    min-height: 1.25em;
  }
}

/* Inline font field: a select-like button that opens the picker. */
.font-field {
  & > .font-field-current {
    width: 100%;
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 8px;
  }
}

/* ═══════════════════════════════════════
   Upload Form
   ═══════════════════════════════════════ */

.upload-form {
  display: flex;
  gap: 8px;
  align-items: end;
  margin-bottom: 24px;
  padding: 16px;
  background: var(--surface-2);
  border: 1px dashed var(--border);
  border-radius: var(--radius);
}

.upload-label {
  flex: 1;
}

/* ═══════════════════════════════════════
   Error Page
   ═══════════════════════════════════════ */

article[data-error-page] {
  text-align: center;

  & > h1 {
    font-size: 48px;
    font-weight: 800;
    color: var(--text-3);
    margin-bottom: 8px;
    letter-spacing: -0.04em;
  }

  & > p {
    margin-bottom: 24px;
  }

  & > a {
    color: var(--accent-text);
    font-size: 13px;
    font-weight: 600;
    text-decoration: none;

    &:hover {
      color: var(--accent-text-hover);
    }
  }
}

/* ═══════════════════════════════════════
   Responsive
   ═══════════════════════════════════════ */

/* Desktop: sidebar nav always visible, override data-show inline style */
@media (min-width: 769px) {
  [data-admin] > #admin-nav {
    display: flex !important;
  }
}

@media (max-width: 768px) {
  .mobile-nav-toggle {
    display: flex;
    background: transparent;
    border: none;
    box-shadow: none;
    color: var(--text-2);
    padding: 4px;
    margin-right: 8px;

    &:hover {
      color: var(--text-1);
      background: var(--surface-3);
    }

    & svg {
      width: 18px;
      height: 18px;
    }
  }

  .mobile-nav-close {
    display: flex;
    margin-left: auto;
    background: transparent;
    border: none;
    box-shadow: none;
    color: var(--text-3);
    padding: 4px;

    &:hover {
      color: var(--text-1);
    }
  }

  [data-admin] {
    grid-template-columns: 1fr;
    grid-template-rows: var(--header-height) 1fr;
    grid-template-areas:
      "header"
      "content";

    & > #admin-nav {
      position: fixed;
      inset: 0;
      z-index: 9999;
      background: var(--backdrop-nav, rgba(0, 0, 0, 0.5));
      backdrop-filter: blur(4px);
      display: flex;
      flex-direction: column;
      animation: nav-overlay-enter var(--duration) var(--ease-out);

      /* Nav content sits on the left side */
      width: 280px;
      background: var(--surface-1);
      border-right: 1px solid var(--border);
      box-shadow: var(--shadow-nav-drawer, 8px 0 24px rgba(0, 0, 0, 0.3));
    }

    & > #admin-page > main,
    & > main {
      padding: 20px 16px;
    }
  }

  aside[aria-label] {
    width: 100%;
  }

  dialog[open] > article {
    width: 95%;
    max-width: none;
    margin: 0 auto;
  }

  /* Header — compact on mobile */
  [data-admin] > header {
    padding: 0 12px;

    & h1 {
      font-size: 16px;
    }
  }

  /* Tables in admin — allow horizontal scroll. The table box scrolls and its
     rows stay one table (the browser wraps them in an anonymous one), so the
     columns line up across rows. Making each row its own fixed-layout table
     broke that, and with a card's min-width:max-content it resolved every
     column to 100,000px. */
  table {
    display: block;
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
  }

  /* Buttons — adequate touch targets */
  button {
    min-height: 40px;
    padding-left: 14px;
    padding-right: 14px;
  }

  /* Bottom sheet — modals slide up from bottom on mobile */
  dialog[open] {
    align-items: flex-end;

    & > article {
      width: 100%;
      max-width: 100%;
      max-height: 85vh;
      border-radius: var(--radius-lg) var(--radius-lg) 0 0;
      margin: 0;
      padding-bottom: calc(16px + env(safe-area-inset-bottom));
      animation: sheet-enter var(--duration-slow) var(--ease-out);
      overflow-y: auto;
      overscroll-behavior: contain;
    }

    & > article::before {
      content: "";
      display: block;
      width: 36px;
      height: 4px;
      background: var(--surface-4);
      border-radius: 2px;
      margin: 8px auto 12px;
    }
  }

  /* Compact mobile header — show only avatar, hide rest */
  [data-admin] > header .header-actions {
    & > nav[aria-label="Language"],
    & > nav.locale-switcher,
    & > .locale-switcher,
    & > .theme-toggle,
    & > button[aria-label="Keyboard shortcuts"],
    & > button.shortcuts-toggle {
      display: none;
    }

    /* Hide username text next to avatar */
    font-size: 0;
    gap: 0;

    & > .user-avatar {
      font-size: 11px;
    }
  }

  /* Content padding for tab bar */
  [data-admin] > #admin-page > main,
  [data-admin] > main {
    padding-bottom: calc(72px + env(safe-area-inset-bottom));
  }
}

/* ═══════════════════════════════════════
   Mobile Tab Bar (bottom navigation)
   ═══════════════════════════════════════ */

#admin-tabbar {
  display: none;
}

@media (max-width: 768px) {
  #admin-tabbar {
    display: flex;
    position: fixed;
    bottom: 0;
    left: 0;
    right: 0;
    z-index: 6000;
    background: var(--surface-1);
    border-top: 1px solid var(--border);
    padding: 6px 0 calc(6px + env(safe-area-inset-bottom));
    justify-content: space-around;
    -webkit-tap-highlight-color: transparent;

    & a, & button {
      display: flex;
      flex-direction: column;
      align-items: center;
      gap: 2px;
      padding: 6px 12px;
      font-size: 10px;
      font-weight: 500;
      font-family: var(--font-sans);
      color: var(--text-3);
      text-decoration: none;
      background: transparent;
      border: none;
      box-shadow: none;
      position: relative;
      transition: color var(--duration-fast) ease;
      min-height: auto;

      & svg {
        width: 20px;
        height: 20px;
        flex-shrink: 0;
      }

      &[aria-current="page"] {
        color: var(--accent-text);
      }

      &:active {
        color: var(--accent-text-hover);
      }
    }

    /* Pinned to the icon's top-right, not the tab's — a tab is as wide as its
       label, so anchoring to the tab left the count floating between two tabs
       looking like part of neither. Big enough to read at arm's length. */
    & mark {
      position: absolute;
      top: 1px;
      left: 50%;
      translate: 3px 0;

      /* The shared mark style prefixes a status dot with ::before — right for
         a pill that reads "● Greidd", wrong for a bare count. Centred in this
         grid it sat above the number, turning the badge into a ring with the
         count pushed out of it. */
      &::before {
        content: none;
      }
      background: var(--danger-solid);
      color: var(--on-accent, white);
      font-size: 10px;
      font-weight: 700;
      min-width: 18px;
      height: 18px;
      border-radius: 9px;
      display: grid;
      place-items: center;
      padding: 0 5px;
      line-height: 1;
      font-variant-numeric: tabular-nums;
      box-shadow: 0 0 0 2px var(--surface-1);
    }
  }
}

/* ═══════════════════════════════════════
   Mobile Utility Classes
   ═══════════════════════════════════════ */

/* Desktop: show desktop-only (natural display), hide mobile-only */
.mobile-only { display: none !important; }

/* Mobile: flip visibility */
@media (max-width: 768px) {
  .desktop-only { display: none !important; }
  .mobile-only  { display: block !important; }
}

/* ═══════════════════════════════════════
   Animations
   ═══════════════════════════════════════ */

@keyframes toast-enter {
  from {
    opacity: 0;
    transform: translateX(40px) scale(0.95);
  }
  to {
    opacity: 1;
    transform: translateX(0) scale(1);
  }
}

@keyframes panel-enter {
  from {
    opacity: 0;
    transform: translateX(20px);
  }
  to {
    opacity: 1;
    transform: translateX(0);
  }
}

@keyframes backdrop-enter {
  from { opacity: 0; }
  to   { opacity: 1; }
}

@keyframes modal-enter {
  from {
    opacity: 0;
    transform: scale(0.96) translateY(8px);
  }
  to {
    opacity: 1;
    transform: scale(1) translateY(0);
  }
}

@keyframes nav-overlay-enter {
  from {
    opacity: 0;
    transform: translateX(-20px);
  }
  to {
    opacity: 1;
    transform: translateX(0);
  }
}

@keyframes sheet-enter {
  from {
    opacity: 0.8;
    transform: translateY(100%);
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
}

/* ═══════════════════════════════════════
   Light Mode
   Supports both OS preference and explicit toggle via data-theme.
   html[data-theme="dark"] forces dark mode (tokens from :root).
   ═══════════════════════════════════════ */

@media (prefers-color-scheme: light) {
  html:not([data-theme="dark"]) {
    /* Surface system — layered light */
    --surface-0: #f8f9fb;
    --surface-1: #ffffff;
    --surface-2: #f1f3f5;
    --surface-3: #e9ecef;
    --surface-4: #dee2e6;
    --surface-raised: #ffffff;

    /* Text hierarchy */
    --text-1: #1a1a2e;
    --text-2: #495057;
    --text-3: #868e96;
    --text-ghost: #ced4da;

    /* Borders */
    --border: rgba(0, 0, 0, 0.08);
    --border-hover: rgba(0, 0, 0, 0.12);

    /* Accent — keep same hue, slightly deeper for contrast */
    --accent-soft: rgba(99, 102, 241, 0.08);
    --accent-glow: rgba(99, 102, 241, 0.15);

    /* Semantic soft backgrounds — lighter for light mode */
    --success-soft: rgba(52, 211, 153, 0.1);
    --warning-soft: rgba(251, 191, 36, 0.1);
    --danger-soft: rgba(248, 113, 113, 0.1);
    --info-soft: rgba(96, 165, 250, 0.1);

    /* The dark scheme's bright fills fall to 1.2–2.5:1 as text here; the
       800 shades hold 5.2:1 or better on their tint over surface-4, the
       darkest surface a badge sits on. */
    --accent-text: #4338ca;
    --accent-text-hover: #3730a3;
    --success-text: #065f46;
    --warning-text: #92400e;
    --danger-text: #991b1b;
    --info-text: #1e40af;
  }
}

html[data-theme="light"] {
  --surface-0: #f8f9fb;
  --surface-1: #ffffff;
  --surface-2: #f1f3f5;
  --surface-3: #e9ecef;
  --surface-4: #dee2e6;
  --surface-raised: #ffffff;
  --text-1: #1a1a2e;
  --text-2: #495057;
  --text-3: #868e96;
  --text-ghost: #ced4da;
  --border: rgba(0, 0, 0, 0.08);
  --border-hover: rgba(0, 0, 0, 0.12);
  --accent-soft: rgba(99, 102, 241, 0.08);
  --accent-glow: rgba(99, 102, 241, 0.15);
  --success-soft: rgba(52, 211, 153, 0.1);
  --warning-soft: rgba(251, 191, 36, 0.1);
  --danger-soft: rgba(248, 113, 113, 0.1);
  --info-soft: rgba(96, 165, 250, 0.1);
  --accent-text: #4338ca;
  --accent-text-hover: #3730a3;
  --success-text: #065f46;
  --warning-text: #92400e;
  --danger-text: #991b1b;
  --info-text: #1e40af;
}

/* The light scheme's softer default shadow, weighted as the plain button
   rule it replaces: a component that sets its own box-shadow on its buttons
   (a segmented toggle, a tab strip, a toolbar) must win over a scheme
   default, as it does in the dark scheme. */
@media (prefers-color-scheme: light) {
  :where(html:not([data-theme="dark"])) button:where(:not(.secondary):not(.ghost)) {
    box-shadow: var(--shadow-button, 0 1px 2px rgba(0, 0, 0, 0.1), inset 0 1px 0 rgba(255, 255, 255, 0.15));
    &:hover { box-shadow: var(--shadow-button-hover, 0 2px 8px rgba(99, 102, 241, 0.25), inset 0 1px 0 rgba(255, 255, 255, 0.2)); }
  }
}
:where(html[data-theme="light"]) button:where(:not(.secondary):not(.ghost)) {
  box-shadow: var(--shadow-button, 0 1px 2px rgba(0, 0, 0, 0.1), inset 0 1px 0 rgba(255, 255, 255, 0.15));
  &:hover { box-shadow: var(--shadow-button-hover, 0 2px 8px rgba(99, 102, 241, 0.25), inset 0 1px 0 rgba(255, 255, 255, 0.2)); }
}

@media (prefers-color-scheme: light) {
  html:not([data-theme="dark"]) [data-admin] > #admin-nav {
    background: var(--nav-surface, #f0f1f5);
    & [role="menuitem"] {
      &:hover { background: var(--nav-item-hover, rgba(0, 0, 0, 0.04)); }
      &[aria-current="page"] { background: var(--nav-item-current, var(--accent-soft)); }
    }
  }
}
html[data-theme="light"] [data-admin] > nav {
  background: var(--nav-surface, #f0f1f5);
  & [role="menuitem"] {
    &:hover { background: var(--nav-item-hover, rgba(0, 0, 0, 0.04)); }
    &[aria-current="page"] { background: var(--nav-item-current, var(--accent-soft)); }
  }
}

@media (prefers-color-scheme: light) {
  html:not([data-theme="dark"]) [data-admin] > [role="status"] [role="alert"] {
    background: var(--surface-1);
    box-shadow: var(--shadow-toast, 0 8px 24px rgba(0, 0, 0, 0.1), 0 2px 8px rgba(0, 0, 0, 0.06));
  }
}
html[data-theme="light"] [data-admin] > [role="status"] [role="alert"] {
  background: var(--surface-1);
  box-shadow: var(--shadow-toast, 0 8px 24px rgba(0, 0, 0, 0.1), 0 2px 8px rgba(0, 0, 0, 0.06));
}

@media (prefers-color-scheme: light) {
  html:not([data-theme="dark"]) aside[aria-label] {
    box-shadow: var(--shadow-panel, -8px 0 24px rgba(0, 0, 0, 0.08), -2px 0 8px rgba(0, 0, 0, 0.04));
  }
}
html[data-theme="light"] aside[aria-label] {
  box-shadow: var(--shadow-panel, -8px 0 24px rgba(0, 0, 0, 0.08), -2px 0 8px rgba(0, 0, 0, 0.04));
}

@media (prefers-color-scheme: light) {
  html:not([data-theme="dark"]) dialog[open] {
    background: var(--backdrop-dialog, rgba(0, 0, 0, 0.25));
    & > article { box-shadow: var(--shadow-dialog, 0 16px 48px rgba(0, 0, 0, 0.12), 0 4px 16px rgba(0, 0, 0, 0.08)); }
  }
}
html[data-theme="light"] dialog[open] {
  background: var(--backdrop-dialog, rgba(0, 0, 0, 0.25));
  & > article { box-shadow: var(--shadow-dialog, 0 16px 48px rgba(0, 0, 0, 0.12), 0 4px 16px rgba(0, 0, 0, 0.08)); }
}

@media (prefers-color-scheme: light) {
  html:not([data-theme="dark"]) body[data-page="login"] {
    &::before { background: radial-gradient(ellipse, var(--login-glow, rgba(99, 102, 241, 0.06)), transparent 70%); }
    & > main > article { box-shadow: var(--shadow-login-card, 0 8px 32px rgba(0, 0, 0, 0.06), 0 2px 8px rgba(0, 0, 0, 0.04)); }
  }
}
html[data-theme="light"] body[data-page="login"] {
  &::before { background: radial-gradient(ellipse, var(--login-glow, rgba(99, 102, 241, 0.06)), transparent 70%); }
  & > main > article { box-shadow: var(--shadow-login-card, 0 8px 32px rgba(0, 0, 0, 0.06), 0 2px 8px rgba(0, 0, 0, 0.04)); }
}

@media (prefers-color-scheme: light) {
  html:not([data-theme="dark"]) ::-webkit-scrollbar-thumb {
    background: var(--surface-4);
    &:hover { background: var(--text-ghost); }
  }
}
html[data-theme="light"] ::-webkit-scrollbar-thumb {
  background: var(--surface-4);
  &:hover { background: var(--text-ghost); }
}

/* ═══════════════════════════════════════
   Scrollbar global
   ═══════════════════════════════════════ */

::-webkit-scrollbar {
  width: 6px;
  height: 6px;
}

::-webkit-scrollbar-track {
  background: transparent;
}

::-webkit-scrollbar-thumb {
  background: var(--surface-4);
  border-radius: 6px;

  &:hover {
    background: var(--text-ghost);
  }
}

/* ═══════════════════════════════════════
   Activity Feed
   ═══════════════════════════════════════ */

[role="feed"] {
  display: flex;
  flex-direction: column;
  gap: 2px;

  & > article {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 10px 14px;
    border-radius: var(--radius-sm);
    transition: background var(--duration-fast) var(--ease-out);

    &:hover {
      background: var(--surface-2);
    }

    & > span[aria-hidden] {
      width: 32px;
      height: 32px;
      display: flex;
      align-items: center;
      justify-content: center;
      flex-shrink: 0;
      background: var(--surface-3);
      border-radius: 50%;
      color: var(--text-2);

      & svg {
        width: 15px;
        height: 15px;
      }
    }

    & > div {
      flex: 1;
      min-width: 0;

      & > p {
        font-size: 13px;
        font-weight: 550;
        color: var(--text-1);
        white-space: nowrap;
        overflow: hidden;
        text-overflow: ellipsis;
      }

      & > small {
        display: block;
        font-size: 12px;
        color: var(--text-3);
        margin-top: 1px;
        white-space: nowrap;
        overflow: hidden;
        text-overflow: ellipsis;
      }
    }

    & > time {
      flex-shrink: 0;
      font-size: 12px;
      color: var(--text-3);
      font-variant-numeric: tabular-nums;
    }
  }
}

/* ═══════════════════════════════════════
   Tabs
   ═══════════════════════════════════════ */

[role="tablist"] {
  display: flex;
  gap: 0;
  border-bottom: 1px solid var(--border);
  margin-bottom: 20px;

  & [role="tab"] {
    padding: 9px 16px;
    border: none;
    border-radius: 0;
    background: transparent;
    box-shadow: none;
    color: var(--text-3);
    font-size: 13px;
    font-weight: 550;
    cursor: pointer;
    position: relative;
    transition:
      color var(--duration-fast) var(--ease-out),
      background var(--duration-fast) var(--ease-out);

    &:hover {
      color: var(--text-1);
      background: var(--surface-2);
    }

    &[aria-selected="true"] {
      color: var(--accent-text-hover);
      background: transparent;

      &::after {
        content: "";
        position: absolute;
        bottom: -1px;
        left: 0;
        right: 0;
        height: 2px;
        background: var(--accent);
        border-radius: 2px 2px 0 0;
      }
    }
  }
}

/* ═══════════════════════════════════════
   Filter Bar
   ═══════════════════════════════════════ */

.filters {
  display: flex;
  align-items: flex-end;
  gap: 12px;
  margin-bottom: 16px;
  flex-wrap: wrap;

  & > label {
    margin-bottom: 0;
    flex: 0 1 auto;
    min-width: 140px;

    & > select {
      background: var(--surface-2);
    }
  }
}

/* ═══════════════════════════════════════
   Key-Value List
   ═══════════════════════════════════════ */

[role="list"][aria-label="Details"],
[role="list"].kv-list {
  display: flex;
  flex-direction: column;
  gap: 0;

  & > [role="listitem"] {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 16px;
    padding: 10px 0;
    border-bottom: 1px solid var(--border);

    &:last-child {
      border-bottom: none;
    }

    & > dt {
      font-size: 13px;
      font-weight: 500;
      color: var(--text-3);
      flex-shrink: 0;
      margin-top: 0;
      text-transform: none;
      letter-spacing: normal;
    }

    & > dd {
      font-size: 13px;
      color: var(--text-1);
      text-align: right;
      padding: 0;
      font-variant-numeric: tabular-nums;
    }
  }
}

/* ═══════════════════════════════════════
   Pagination
   ═══════════════════════════════════════ */

nav[aria-label="Pagination"],
nav[data-pagination] {
  margin-top: 20px;
  display: flex;
  justify-content: center;

  & ol {
    display: flex;
    align-items: center;
    gap: 4px;
    list-style: none;

    & li {
      & span[aria-hidden] {
        padding: 4px 6px;
        color: var(--text-ghost);
        font-size: 13px;
        user-select: none;
      }
    }

    & button {
      min-width: 32px;
      padding: 5px 10px;
      font-size: 13px;
      font-variant-numeric: tabular-nums;
      background: var(--surface-3);
      border-color: var(--border);
      color: var(--text-1);
      box-shadow: none;

      &[aria-current="page"] {
        background: var(--accent-soft);
        color: var(--accent-text-hover);
        border-color: transparent;
        cursor: default;

        &:hover {
          background: var(--accent-soft);
        }

        &:active {
          transform: none;
        }
      }

      &:disabled {
        opacity: 0.35;
        cursor: not-allowed;

        &:active {
          transform: none;
        }
      }
    }
  }
}

/* ═══════════════════════════════════════
   Breadcrumbs
   ═══════════════════════════════════════ */

nav[aria-label="Breadcrumb"],
nav.breadcrumbs {
  & ol {
    display: flex;
    align-items: center;
    gap: 6px;
    list-style: none;
    font-size: 13px;
  }

  & a {
    color: var(--text-3);
    cursor: pointer;
    text-decoration: none;

    &:hover {
      color: var(--text-1);
    }
  }

  & [aria-current] {
    color: var(--text-1);
    font-weight: 500;
  }

  & [aria-hidden] {
    color: var(--text-ghost);
  }
}

/* ═══════════════════════════════════════
   Notification Bell & Dropdown
   ═══════════════════════════════════════ */

.notif-wrap {
  display: inline-flex;
}

.notif-bell {
  position: relative;
  background: transparent;
  border: none;
  box-shadow: none;
  color: var(--text-3);
  padding: 4px;
  cursor: pointer;

  &:hover {
    color: var(--text-1);
    background: var(--surface-3);
  }

  & svg {
    width: 16px;
    height: 16px;
  }
}

.notif-badge {
  position: absolute;
  top: -2px;
  right: -4px;
  min-width: 16px;
  height: 16px;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 0 4px;
  border-radius: 10px;
  background: var(--danger-solid);
  color: var(--on-accent, white);
  font-size: 10px;
  font-weight: 700;
  line-height: 1;

  /* The span is always in the DOM (its own SSE morph target); at zero it
     renders empty and disappears. */
  &:empty {
    display: none;
  }
}

/* The bell's spoken name: read by assistive technology, never drawn. */
.notif-label {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

.notif-dropdown {
  /* Fixed, not absolute: the wrapper lives inside the header flex row, so
     viewport anchoring is the only placement that cannot be skewed by an
     intermediate positioned ancestor. */
  position: fixed;
  top: calc(var(--header-height) - 4px);
  right: 16px;
  width: 340px;
  max-width: calc(100vw - 32px);
  max-height: 400px;
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  box-shadow: var(--shadow-dropdown,
    0 8px 24px rgba(0, 0, 0, 0.4),
    0 2px 8px rgba(0, 0, 0, 0.2));
  z-index: 6000;
  overflow: hidden;
  animation: modal-enter var(--duration) var(--ease-out);
  /* A column whose list is the only part that shrinks: the footer links
     state the totals the badge counts past each cap, so the box's
     max-height must clip the scrolling list, never a footer link. */
  display: flex;
  flex-direction: column;

  & > header {
    flex-shrink: 0;
    padding: 12px 16px;
    border-bottom: 1px solid var(--border);
    font-size: 13px;
  }

  & ul {
    list-style: none;
    max-height: 340px;
    min-height: 0;
    overflow-y: auto;

    /* Rows are variable height, so the cut always lands mid-row. Without a
       visible scrollbar that reads as a broken layout rather than "there is
       more below" — and macOS overlay scrollbars are invisible until you
       already scroll. Reserve the gutter and keep the thumb permanent so the
       affordance is there before the first interaction. */
    scrollbar-gutter: stable;
    scrollbar-width: thin;
    scrollbar-color: var(--surface-4) transparent;

    &::-webkit-scrollbar { width: 4px; }
    &::-webkit-scrollbar-thumb {
      background: var(--surface-4);
      border-radius: 4px;
    }
  }

  & li {
    display: flex;
    align-items: flex-start;
    gap: 12px;
    padding: 10px 16px;
    border-bottom: 1px solid var(--border);
    font-size: 13px;
    transition: background var(--duration-fast) var(--ease-out);

    &:last-child {
      border-bottom: none;
    }

    &:hover {
      background: var(--surface-3);
    }

    &[data-unread="true"] {
      background: var(--accent-soft);
    }

    &[data-level="success"] .notif-content strong { color: var(--success-text); }
    &[data-level="warning"] .notif-content strong { color: var(--warning-text); }
    &[data-level="error"] .notif-content strong { color: var(--danger-text); }
    &[data-level="info"] .notif-content strong { color: var(--info-text); }

    /* A linked row keeps the plain row's layout; the whole row is the target. */
    & > a {
      display: flex;
      align-items: flex-start;
      gap: 12px;
      flex: 1;
      min-width: 0;
      color: inherit;
      text-decoration: none;
    }
  }

  & .notif-content {
    flex: 1;
    min-width: 0;

    & strong {
      display: block;
      font-size: 13px;
      font-weight: 600;
      color: var(--text-1);
    }

    & p {
      font-size: 12px;
      color: var(--text-3);
      margin-top: 2px;
      line-height: 1.4;
    }
  }

  & time {
    flex-shrink: 0;
    font-size: 11px;
    color: var(--text-ghost);
    font-variant-numeric: tabular-nums;
  }

  & > footer {
    flex-shrink: 0;
    border-top: 1px solid var(--border);
    text-align: center;

    & > a {
      display: block;
      padding: 10px 16px;
      font-size: 13px;
      font-weight: 600;
      color: var(--accent-text);
      text-decoration: none;

      &:hover {
        background: var(--surface-3);
      }
    }
  }

  & .notif-empty {
    padding: 24px 16px;
    text-align: center;
    color: var(--text-3);
    font-size: 13px;
  }
}

/* Destructive confirmation zone (e.g. the close-store page): visibly not a
   normal settings section. */
.closure-danger {
  margin-top: 24px;
  padding: 16px 20px;
  border: 1px solid var(--danger);
  border-radius: var(--radius);
  background: color-mix(in srgb, var(--danger) 6%, transparent);

  & h3 {
    color: var(--danger-text);
  }

  & label {
    display: block;
    margin: 12px 0;
  }
}

/* ═══════════════════════════════════════
   Theme Toggle
   ═══════════════════════════════════════ */

.theme-toggle {
  position: relative;
  background: transparent;
  border: none;
  box-shadow: none;
  color: var(--text-3);
  padding: 4px;
  cursor: pointer;
  width: 28px;
  height: 28px;
  overflow: hidden;

  &:hover {
    color: var(--text-1);
    background: var(--surface-3);
  }

  & svg {
    width: 16px;
    height: 16px;
  }
}

/* Dark mode (default): show sun icon to switch to light */
.theme-icon-light { display: inline-flex; }
.theme-icon-dark { display: none; }

/* Light mode: show moon icon to switch to dark */
@media (prefers-color-scheme: light) {
  html:not([data-theme="dark"]) {
    .theme-icon-light { display: none; }
    .theme-icon-dark { display: inline-flex; }
  }
}
html[data-theme="light"] {
  .theme-icon-light { display: none; }
  .theme-icon-dark { display: inline-flex; }
}
html[data-theme="dark"] {
  .theme-icon-light { display: inline-flex; }
  .theme-icon-dark { display: none; }
}

/* Header actions container */
.header-actions {
  display: flex;
  align-items: center;
  gap: 6px;

  & nav[aria-label="Language"],
  & nav.locale-switcher,
  & .locale-switcher {
    display: flex;
    background: var(--surface-3);
    border-radius: var(--radius-sm);
    overflow: hidden;

    & button {
      background: none;
      border: none;
      padding: 4px 10px;
      font-size: 11px;
      font-weight: 500;
      color: var(--text-2);
      cursor: pointer;
      transition: all var(--transition);

      &:not(:last-child) { border-right: 1px solid var(--border); }
      &:hover { color: var(--text-1); }
      &[aria-current="true"] {
        background: var(--accent-solid);
        color: var(--on-accent, white);
        cursor: default;
      }
    }
  }
}

/* ═══════════════════════════════════════
   Date Picker / Date Range
   ═══════════════════════════════════════ */

input[type="date"] {
  color-scheme: dark;
}

@media (prefers-color-scheme: light) {
  html:not([data-theme="dark"]) input[type="date"] {
    color-scheme: light;
  }
}
html[data-theme="light"] input[type="date"] {
  color-scheme: light;
}

.date-range {
  display: flex;
  align-items: flex-end;
  gap: 12px;

  & > label {
    flex: 1;
    margin-bottom: 16px;
  }
}

/* ═══════════════════════════════════════
   Tag Input / Multi-Select
   ═══════════════════════════════════════ */


/* ═══════════════════════════════════════
   Map Component (Leaflet)
   ═══════════════════════════════════════ */

.leaflet-map {
  border-radius: var(--radius);
  border: 1px solid var(--border);
  margin-bottom: 16px;
  z-index: 0;
}

/* ═══════════════════════════════════════
   Calendar View
   ═══════════════════════════════════════ */

.calendar {
  background: var(--surface-1);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  overflow: hidden;
  margin-bottom: 16px;
}

.calendar-header {
  padding: 14px 18px;
  border-bottom: 1px solid var(--border);
  display: flex;
  align-items: center;
  justify-content: space-between;
}

.calendar-title {
  font-size: 14px;
  font-weight: 650;
  color: var(--text-1);
  letter-spacing: -0.01em;
}

.calendar-grid {
  display: grid;
  grid-template-columns: repeat(7, 1fr);
}

.calendar-dow {
  padding: 8px 4px;
  text-align: center;
  font-size: 11px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--text-3);
  border-bottom: 1px solid var(--border);
  background: var(--surface-2);
  user-select: none;
}

.calendar-day {
  min-height: 80px;
  padding: 4px 0;
  border-right: 1px solid var(--border);
  border-bottom: 1px solid var(--border);
  position: relative;
  overflow: hidden;
  transition: background var(--duration-fast) var(--ease-out);

  &:nth-child(7n + 14) {
    border-right: none;
  }

  &:hover {
    background: var(--surface-2);
  }

  & > [aria-hidden] {
    display: block;
    height: 20px;
    margin: 1px 0;
  }
}

.calendar-day-blank {
  background: var(--surface-2);
  opacity: 0.5;
}

.calendar-day-today {
  background: var(--accent-soft);

  & .calendar-day-num {
    background: var(--accent-solid);
    color: var(--on-accent, white);
    border-radius: 50%;
    width: 24px;
    height: 24px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
  }
}

.calendar-day-num {
  font-size: 12px;
  font-weight: 600;
  color: var(--text-2);
  font-variant-numeric: tabular-nums;
  padding: 0 8px;
  display: block;
  margin-bottom: 2px;
}

.calendar-events {
  display: flex;
  gap: 3px;
  margin-top: 4px;
  flex-wrap: wrap;
}

.calendar-event {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--text-3);
  flex-shrink: 0;

  &[data-variant="success"] { background: var(--success); }
  &[data-variant="info"] { background: var(--info); }
  &[data-variant="warning"] { background: var(--warning); }
  &[data-variant="danger"] { background: var(--danger); }
}

.calendar-bar {
  display: block;
  height: 20px;
  line-height: 20px;
  border-radius: 0;
  margin: 1px 0;
  padding: 0;
  background: var(--info-solid);
  cursor: pointer;
  font-size: 10px;
  font-weight: 600;
  letter-spacing: 0.01em;
  color: var(--on-accent, white);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  text-decoration: none;
  transition: filter var(--duration-fast) var(--ease-out);

  &:hover { filter: brightness(0.9); }

  &[data-variant="discount"] { background: var(--accent-solid); }
  &[data-variant="sale"] { background: var(--success-solid); }

  /* Extend bars into cell borders to create seamless connection */
  &[data-start] {
    margin-left: 6px;
    padding-left: 6px;
    border-radius: 4px 0 0 4px;
    margin-right: -1px;
  }
  &[data-middle] {
    margin-left: -1px;
    margin-right: -1px;
  }
  &[data-end] {
    margin-right: 6px;
    margin-left: -1px;
    border-radius: 0 4px 4px 0;
  }
  &[data-single] {
    margin-left: 6px;
    margin-right: 6px;
    padding-left: 6px;
    border-radius: 4px;
  }

  /* Row-start: bar continues from previous week, show label with left margin */
  &[data-row-start] {
    margin-left: 6px;
    padding-left: 6px;
    border-radius: 4px 0 0 4px;
    margin-right: -1px;
  }

  /* Row-end: bar continues to next week, flush right */
  &[data-row-end] {
    margin-left: -1px;
    margin-right: 0;
    border-radius: 0;
  }

  /* Both row-start and row-end (single day that continues both ways) */
  &[data-row-start][data-row-end] {
    margin-left: 6px;
    margin-right: 0;
    border-radius: 4px 0 0 4px;
  }
}

.calendar-legend {
  display: flex;
  gap: 16px;
  padding: 12px 18px;
  border-top: 1px solid var(--border);
  font-size: 12px;
  color: var(--text-2);

  & > span {
    display: flex;
    align-items: center;
    gap: 6px;

    &::before {
      content: '';
      width: 10px;
      height: 6px;
      border-radius: 3px;
      display: inline-block;
    }
  }

  & > span:first-child::before { background: var(--accent-solid); }
  & > span:nth-child(2)::before { background: var(--success-solid); }
}

.calendar-sidebar {
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.calendar-sidebar-item {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 10px 14px;
  background: var(--surface-1);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  font-size: 13px;
  color: var(--text-1);
  text-decoration: none;
  transition: background var(--duration-fast) var(--ease-out);

  &:hover { background: var(--surface-2); }

  & > .dot {
    width: 8px;
    height: 8px;
    border-radius: 50%;
    flex-shrink: 0;
  }

  & > .dot[data-variant="discount"] { background: var(--accent-solid); }
  & > .dot[data-variant="sale"] { background: var(--success-solid); }

  & > .meta {
    margin-left: auto;
    font-size: 11px;
    color: var(--text-3);
    font-variant-numeric: tabular-nums;
  }
}

/* ═══════════════════════════════════════
   Keyboard Shortcuts Modal
   ═══════════════════════════════════════ */

#admin-shortcuts {
  /* data-show handles visibility; when hidden, display:none */

  & .shortcuts-list {
    display: flex;
    flex-direction: column;
    gap: 0;

    & > div {
      display: flex;
      align-items: center;
      justify-content: space-between;
      padding: 10px 0;
      border-bottom: 1px solid var(--border);

      &:last-child {
        border-bottom: none;
      }
    }

    & dt {
      margin-top: 0;
      text-transform: none;
      letter-spacing: normal;
    }

    & dd {
      font-size: 13px;
      color: var(--text-2);
      padding: 0;
    }
  }

  & kbd {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 24px;
    height: 24px;
    padding: 0 8px;
    border-radius: var(--radius-sm);
    background: var(--surface-3);
    border: 1px solid var(--border);
    font-family: var(--font-mono);
    font-size: 12px;
    font-weight: 600;
    color: var(--text-1);
  }
}

/* ═══════════════════════════════════════
   Detail Cards — section-based editing
   ═══════════════════════════════════════ */

.admin-card {
  background: var(--surface-3);
  border: 1px solid var(--border-hover);
  border-radius: var(--radius-md);
  padding: 1.25rem;
  margin-bottom: 0.75rem;

  & > header {
    display: flex;
    justify-content: space-between;
    align-items: center;
    margin-bottom: 1rem;
  }

  & > header > h3 {
    margin: 0;
    font-size: 0.9375rem;
    font-weight: 600;
    letter-spacing: -0.01em;
  }

  & > p {
    font-size: 0.875rem;
    margin: 0;
  }
}

/* 2-column grid definition list for detail cards */
dl.admin-dl {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 0.75rem 2rem;
  margin: 0;

  & > div { min-width: 0; }
  & > div.full { grid-column: 1 / -1; }

  & dt {
    font-size: 11px;
    font-weight: 600;
    color: var(--text-3);
    text-transform: uppercase;
    letter-spacing: 0.05em;
    margin: 0 0 2px 0;
  }

  & dd {
    font-size: 13px;
    color: var(--text-1);
    margin: 0;
    padding: 0;
  }
}

/* Inline edit forms within cards */
.edit-form {
  display: flex;
  flex-direction: column;
  gap: 0.75rem;

  & label > span {
    display: block;
    font-size: 0.75rem;
    font-weight: 600;
    color: var(--text-3);
    margin-bottom: 4px;
  }
}

.form-row {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 0.75rem;
}

.edit-actions {
  display: flex;
  /* Full-size buttons with Icelandic labels outgrow a phone card; a row
     that cannot wrap sets the card's minimum width and pushes it off-screen. */
  flex-wrap: wrap;
  gap: 0.5rem;
  justify-content: flex-end;
  padding-top: 0.25rem;
}

/* Touch. iOS Safari zooms the page into any focused control whose text is
   under 16px, so every field on a phone admin zoomed and had to be pinched
   back. A thumb needs a 44px target for the save it came to press. Both hold
   at the phone breakpoint and on any coarse pointer: a tablet is wider than
   768px and zooms the same. The font-size is !important because component
   rules and inline styles set 12-14px on their own controls, and none of
   them may win on a touch screen. The command palette's larger input is
   left alone: it already clears 16px. */
@media (max-width: 768px), (pointer: coarse) {
  input:not([type="checkbox"], [type="radio"], [type="range"], [type="color"], .cmdk-input),
  select,
  textarea {
    font-size: max(16px, 1rem) !important;
  }

  /* Every filled or outlined button is a touch target: the saves inline
     beside a field, in a modal or in a table cell as much as those in a
     section's edit row, and the compact ones too. .small is a size for the
     eye; a thumb on a phone needs 44px whatever the label's size. A ghost
     stays compact on purpose: it is an inline helper inside a row, a chip
     or a field, except the ghost helpers in an edit row, which sit beside
     the save at its height and must beat the compact min-height the
     ecommerce sheet gives ghosts. */
  [data-admin] button:not(.ghost),
  .edit-actions button.ghost,
  .notes-section > button {
    min-height: 44px;
  }

  /* The close of a dialog, panel or alert is a ghost, but it is the way
     out and sits alone in its corner, so it gets the full square. A dialog
     shown by data-show has no open attribute, so the rule does not ask for
     one. */
  dialog > article > header > button.ghost,
  aside[aria-label] > header > button.ghost,
  #admin-fetch-alert > button.ghost {
    min-width: 44px;
    min-height: 44px;
  }
}

/* --- Searchable Single-Select ---
   Server-driven picker variant that manages one ID at a time. Shares the
   search-input + options-list structure with the multi-select, but has no
   chip row — the parent template shows the current value, and clicks set
   the scalar signal client-side. */
.searchable-single-select {
  display: flex;
  flex-direction: column;
  gap: 8px;
  margin-bottom: 16px;

  & > label {
    display: flex;
    flex-direction: column;
    gap: 4px;

    & > span {
      font-size: 12px;
      font-weight: 600;
      color: var(--text-2);
      letter-spacing: 0.01em;
    }

    & > input[type="search"] {
      width: 100%;
    }
  }

  & > ul[role="listbox"] {
    max-height: 220px;
    overflow-y: auto;
    background: var(--surface-1);
    border: 1px solid var(--border-color, var(--border));
    border-radius: var(--radius-2, var(--radius));
    box-shadow: var(--shadow-3);
    list-style: none;
    margin: 0;
    padding: 4px;

    & > li {
      padding: 8px 12px;
      border-radius: var(--radius-1, 4px);
      font-size: 13px;
      cursor: pointer;
      transition: background var(--duration-fast) var(--ease-out);

      &[role="option"]:not([aria-disabled="true"]):hover,
      &[role="option"][tabindex]:focus-visible {
        background: var(--surface-3);
      }

      &[role="option"][tabindex]:focus-visible {
        outline: 2px solid var(--accent);
        outline-offset: -2px;
      }

      &[role="option"][aria-selected="true"] {
        background: var(--accent-soft);
        color: var(--accent-text-hover);
        font-weight: 550;

        &::before {
          content: "✓";
          display: inline-block;
          margin-right: 6px;
          color: var(--accent-text);
        }
      }

      &[aria-disabled="true"] {
        color: var(--text-2);
        font-style: italic;
        cursor: default;
        text-align: center;
      }
    }
  }
}

/* --- Searchable Multi-Select ---
   Server-driven picker: search input debounces to an SSE endpoint that
   morphs the whole <section> back. The two child <ul>s are distinguished
   by role — role="list" carries the selected chips, role="listbox" carries
   the filtered options. */
.searchable-multi-select {
  display: flex;
  flex-direction: column;
  gap: 8px;
  margin-bottom: 16px;

  & > label {
    display: flex;
    flex-direction: column;
    gap: 4px;

    & > span {
      font-size: 12px;
      font-weight: 600;
      color: var(--text-2);
      letter-spacing: 0.01em;
    }

    & > input[type="search"] {
      width: 100%;
    }
  }

  & > ul[role="list"] {
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
    list-style: none;
    margin: 0;
    padding: 0;

    & > li {
      display: inline-flex;
      align-items: center;
      gap: 4px;
      padding: 2px 2px 2px 10px;
      border-radius: 999px;
      background: var(--accent-soft);
      border: 1px solid var(--accent);
      color: var(--accent-text-hover);
      font-size: 12px;
      font-weight: 550;

      & > mark {
        background: transparent;
        color: inherit;
        padding: 0;
      }

      & > button {
        display: inline-flex;
        align-items: center;
        justify-content: center;
        width: 20px;
        height: 20px;
        padding: 0;
        border-radius: 50%;
        font-size: 11px;
        line-height: 1;
        color: inherit;

        &:hover {
          background: var(--accent-solid);
          color: var(--on-accent, white);
        }
      }
    }
  }

  & > ul[role="listbox"] {
    max-height: 220px;
    overflow-y: auto;
    background: var(--surface-1);
    border: 1px solid var(--border-color, var(--border));
    border-radius: var(--radius-2, var(--radius));
    box-shadow: var(--shadow-3);
    list-style: none;
    margin: 0;
    padding: 4px;

    & > li {
      padding: 8px 12px;
      border-radius: var(--radius-1, 4px);
      font-size: 13px;
      cursor: pointer;
      transition: background var(--duration-fast) var(--ease-out);

      &[role="option"]:not([aria-disabled="true"]):hover,
      &[role="option"][tabindex]:focus-visible {
        background: var(--surface-3);
      }

      &[role="option"][tabindex]:focus-visible {
        outline: 2px solid var(--accent);
        outline-offset: -2px;
      }

      &[aria-disabled="true"] {
        color: var(--text-2);
        font-style: italic;
        cursor: default;
        text-align: center;
      }
    }
  }
}

/* ============================================
   Theme Builder — Split-pane customizer
   ============================================ */
.theme-builder {
  display: flex;
  flex-direction: column;
  height: calc(100vh - 3.5rem);
  margin: calc(var(--admin-gap, 1.5rem) * -1);
}

/* On a narrow window the tabs and the page actions wrap onto two rows
   rather than pushing the preview toggles and Publish off the edge. */
.builder-toolbar {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  align-items: center;
  gap: 0.5rem;
  padding: 0.5rem 1rem;
  border-block-end: 1px solid var(--border, #e0e0e0);
  background: var(--surface-1, #fff);
  flex-shrink: 0;
}

.builder-tabs {
  display: flex;
  background: var(--surface-2, #f5f5f5);
  border-radius: 6px;
  padding: 2px;

  & button {
    padding: 0.375rem 1rem;
    font-size: 0.8125rem;
    font-weight: 500;
    border-radius: 4px;
    background: none;
    color: var(--text-2, #666);
    border: none;
    cursor: pointer;

    &.active {
      background: var(--surface-1, #fff);
      color: var(--text-1, #111);
      box-shadow: var(--shadow-tab-active, 0 1px 3px oklch(0 0 0 / 0.08));
    }
  }
}

.builder-actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.5rem;
}

.device-toggle {
  display: flex;
  gap: 2px;
  background: var(--surface-2, #f5f5f5);
  border-radius: 6px;
  padding: 2px;

  & button.active {
    background: var(--surface-1, #fff);
    box-shadow: var(--shadow-tab-active, 0 1px 3px oklch(0 0 0 / 0.08));
  }
}

.builder-panes {
  display: grid;
  /* Edit panel scales with the window (never too cramped for section rows + the add-section
     grid), preview takes the rest. */
  grid-template-columns: clamp(440px, 30%, 560px) 1fr;
  flex: 1;
  overflow: hidden;
  position: relative; /* anchor for the quick-edit overlay panel */
}

/* Quick-edit mode: a focused, full-width editor for simple content pages (Terms/About)
   where the iframe adds little. The panel OVERLAYS the preview rather than hiding it, so the
   preview keeps its measured width and re-fits correctly the moment quick-edit is toggled off. */
.theme-builder.quick-edit .builder-panel {
  position: absolute;
  inset: 0;
  z-index: 5;
  background: var(--surface, #fff);
  border-inline-end: none;
  /* Cover the whole panes area so the (still-measured) preview underneath is hidden,
     and center the editor content to a comfortable reading width. */
  padding-inline: max(1.5rem, calc((100% - 860px) / 2));
}

.builder-panel {
  overflow-y: auto;
  border-inline-end: 1px solid var(--border, #e0e0e0);
  padding: 1rem;
}

.builder-preview {
  background: var(--surface-2, #f5f5f5);
  display: flex;
  justify-content: center;
  align-items: flex-start;
  padding: 1rem;
  overflow: hidden;
  position: relative;

  /* Desktop renders a real 1440px desktop viewport scaled to fit the pane (size/transform set
     by Datastar from the measured pane, since CSS can't compute a unitless scale from a width).
     This fills the pane AND shows the page proportionally — not a tiny box, not a 1:1 zoom-in. */
  & iframe {
    flex-shrink: 0; /* keep the 1440px logical width — the transform does the fitting, not flexbox */
    border: 1px solid var(--border, #e0e0e0);
    border-radius: 8px;
    background: var(--preview-surface, oklch(0.99 0 0));
    transform-origin: top center;
  }

  /* Mobile preview is a centred phone frame filling the available height. */
  &.mobile iframe {
    width: 390px;
    height: 100%;
    max-height: 860px;
    transform: none;
    border-radius: 24px;
    box-shadow: var(--shadow-phone-frame, 0 8px 32px oklch(0 0 0 / 0.12));
  }
}

.builder-sections h3,
.builder-add-section h4 {
  font-size: 0.6875rem;
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--text-2, #666);
  margin-block-end: 0.75rem;
}

.builder-section-item {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.5rem 0.625rem;
  border: 1px solid var(--border, #e0e0e0);
  border-radius: 6px;
  margin-block-end: 0.375rem;
  background: var(--surface-1, #fff);

  &:hover { border-color: var(--text-2, #999); }
  /* A hidden section can still be shown, moved or removed, so its row stays
     readable (dimming the whole row failed contrast); the tint and its
     hidden badge say it is off. */
  &.hidden-section {
    background: var(--surface-2, #f5f5f5);

    & .badge-muted { color: var(--text-1, #111); }
  }
  &.drag-over {
    position: relative;

    &::before {
      content: "";
      position: absolute;
      top: -3px;
      left: 0;
      right: 0;
      height: 3px;
      background: var(--brand-1, #4a6cf7);
      border-radius: 2px;
    }
  }

  &.dragging {
    opacity: 0.4;
  }
}

.section-drag-handle {
  color: var(--text-2, #999);
  cursor: grab;
  flex-shrink: 0;
}

.section-info {
  flex: 1;
  min-width: 0;

  & strong { font-size: 0.8125rem; font-weight: 500; }

  /* A row named by the section's own heading says its type on a muted line
     under it. */
  & > small[data-part="section-type"] {
    display: block;
    margin-block-start: 0.125rem;
    font-size: 0.6875rem;
    color: var(--text-2, #666);
  }

  & .badge-muted {
    font-size: 0.625rem;
    padding: 0.125rem 0.375rem;
    background: var(--surface-2, #f5f5f5);
    border-radius: 3px;
    color: var(--text-2, #666);
    margin-inline-start: 0.375rem;
  }
}

.section-actions {
  display: flex;
  gap: 2px;
  flex-shrink: 0;

  & button {
    padding: 0.25rem;
    color: var(--text-2, #999);
    &:hover { color: var(--text-1, #111); }
  }
}

.builder-add-section { margin-block-start: 1.5rem; }

/* What a theme switch hid, per theme it waits for: a collapsed group below
   the page's own rows, so trying several themes does not bury the sections
   the merchant hid by hand. */
#section-list {
  & > details[data-kept-theme] {
    margin-block: 0.75rem 0.375rem;
    border: 1px dashed var(--border, #e0e0e0);
    border-radius: 6px;
    padding: 0.25rem 0.5rem;

    & > summary {
      cursor: pointer;
      padding: 0.375rem 0.125rem;
      font-size: 0.8125rem;
      font-weight: 500;
      color: var(--text-1, #111);

      & .badge-muted {
        font-size: 0.625rem;
        padding: 0.125rem 0.375rem;
        background: var(--surface-2, #f5f5f5);
        border-radius: 3px;
        color: var(--text-1, #111);
        margin-inline-start: 0.375rem;
      }
    }

    &[open] > summary { margin-block-end: 0.375rem; }
  }

  & > p[role="status"] {
    margin-block: 0 0.5rem;
    font-size: 0.8125rem;
    color: var(--text-1, #111);
  }
}

/* The builder's questions (remove a section, discard the draft) and its
   schedule picker: small dialogs in the top layer, so the row's narrow action
   cluster and the toolbar never have to make room for them. Shown only while
   open: a browser without popovers never shows them, so a remove does nothing
   rather than skip its question. */
:is(.builder-section-item, #theme-editor > .page-header) > [popover][role="alertdialog"],
.builder-schedule > [popover][role="dialog"] {
  display: none;
}

.builder-schedule > [popover][role="dialog"]:popover-open > label {
  display: grid;
  gap: 0.25rem;
  margin: 0 0 0.75rem;
  font-size: 0.875rem;
}

:is(.builder-section-item, #theme-editor > .page-header) > [popover][role="alertdialog"]:popover-open,
.builder-schedule > [popover][role="dialog"]:popover-open {
  display: block;
  /* The admin's reset zeroes every margin, which pins a popover to the
     top-left corner; restore the centring the browser would give it. */
  position: fixed;
  inset: 0;
  margin: auto;
  height: fit-content;
  max-width: min(24rem, calc(100vw - 2rem));
  padding: 1rem;
  border: 1px solid var(--border, #e0e0e0);
  border-radius: 8px;
  background: var(--surface-1, #fff);
  color: var(--text-1, #111);
  box-shadow: 0 8px 24px rgb(0 0 0 / 0.18);

  & > p { margin: 0 0 0.75rem; font-size: 0.875rem; line-height: 1.4; }
  & > footer { display: flex; justify-content: flex-end; gap: 0.5rem; flex-wrap: wrap; }
  &::backdrop { background: rgb(0 0 0 / 0.25); }
}

/* The section an add just placed: the list scrolls to it and rings it for a
   moment, so the owner sees where it landed. */
.builder-section-item[data-just-added] {
  animation: builder-just-added 2.4s ease-out;

  @media (prefers-reduced-motion: reduce) {
    animation: none;
    outline: 2px solid var(--accent, #6366f1);
  }
}

@keyframes builder-just-added {
  from { box-shadow: 0 0 0 3px var(--accent, #6366f1); }
  to { box-shadow: 0 0 0 3px transparent; }
}

/* A placed section that does not render as itself under the store's theme
   (another theme's, retired, unknown) keeps its row, dashed. */
.builder-section-item[data-section-case]:not([data-section-case="own"]) {
  border-style: dashed;
}

/* Any badged row, such a section or the store's own whose data the store
   lacks, says why in a compact badge and a muted line under the name. Its
   actions wrap under it on a narrow pane, where the badge, the line and the
   convert button's label need the room. */
.builder-section-item:has(> .section-info > mark) {
  flex-wrap: wrap;

  & > .section-info {
    flex: 1 1 12rem;

    & > mark {
      margin-inline-start: 0.375rem;
      padding: 1px 7px;
      font-size: 10px;
      vertical-align: 1px;
    }

    & > small {
      display: block;
      margin-block-start: 0.125rem;
      font-size: 0.6875rem;
      color: var(--text-2, #666);
    }
  }

  & > .section-actions {
    margin-inline-start: auto;

    & > button.secondary {
      padding: 0.25rem 0.625rem;
      font-size: 0.6875rem;
      color: var(--text-1, #111);
    }
  }
}

/* The add grid in groups: the active theme's own sections first, then the
   shared ones by category. */
.add-section-group {
  margin-block-end: 0.875rem;

  & > h5 {
    margin: 0 0 0.375rem;
    font-size: 0.6875rem;
    font-weight: 600;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--text-2, #666);
  }

  &[data-group="theme"] > h5 { color: var(--text-1, #111); }
}

.add-section-grid {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 0.375rem;
}

.add-section-btn {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.375rem;
  padding: 0.75rem 0.5rem;
  border: 1px dashed var(--border, #ddd);
  border-radius: 6px;
  background: none;
  cursor: pointer;
  font-size: 0.6875rem;
  color: var(--text-2, #666);

  &:hover {
    border-color: var(--brand-1, #4a6cf7);
    background: var(--brand-soft, oklch(0.97 0.01 250));
    color: var(--text-1, #111);
  }

  & svg { width: 20px; height: 20px; }

  & small {
    font-size: 0.625rem;
    line-height: 1.3;
    text-align: center;
  }

  /* A section whose data the store lacks is listed, not addable. */
  &:disabled {
    cursor: not-allowed;
    opacity: 0.6;

    &:hover {
      border-color: var(--border, #ddd);
      background: none;
      color: var(--text-2, #666);
    }
  }
}

/* Constrain the settings form so the label↔control pairs read as a tidy form
   instead of being flung to opposite edges of the wide builder pane. */
.builder-design {
  max-width: 460px;
}

.builder-design h3 {
  font-size: 0.6875rem;
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--text-2, #666);
  margin-block-end: 1rem;
}

/* One overridable colour or font token: the merchant's switch, the theme's
   value beside it, and the override value, disabled while the switch is off.
   Shared by the settings cards and the builder's design panel. */
fieldset.token-override {
  border: 1px solid var(--surface-3);
  border-radius: 6px;
  padding: 0.5rem 0.75rem;
  margin: 0 0 0.75rem;
  display: grid;
  gap: 0.25rem;

  & > legend {
    font-size: 0.8125rem;
    font-weight: 600;
    padding-inline: 0.25rem;
    margin: 0;
  }

  & > .token-theme-value {
    display: flex;
    align-items: center;
    gap: 0.375rem;
    margin: 0;
    font-size: 0.75rem;
    color: var(--text-2, #666);
  }

  & > fieldset.token-value {
    border: none;
    padding: 0;
    margin: 0;
    min-inline-size: 0;

    & > label {
      display: flex;
      align-items: center;
      justify-content: space-between;
      gap: 0.75rem;
    }

    /* The switch is off: the value is the theme's and cannot be edited. */
    &:disabled {
      opacity: 0.55;
    }
  }

  /* A picker, not a text field: the shared input width would stretch the
     sample into a hairline. */
  & input[type="color"] {
    inline-size: 40px;
    block-size: 28px;
    padding: 2px;
    border: 1px solid var(--surface-3);
    border-radius: 4px;
    cursor: pointer;
  }
}

.settings-value > mark,
.settings-value > small {
  margin-inline-start: 0.5rem;
  font-size: 0.75rem;
}

.settings-value > small {
  color: var(--text-2, #666);
}

.design-group {
  border: none;
  padding: 0;
  margin: 0 0 1.5rem;

  & legend {
    font-size: 0.75rem;
    font-weight: 600;
    color: var(--text-1, #111);
    margin-block-end: 0.75rem;
  }

  & label {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 0.75rem;
    padding: 0.375rem 0;

    & span { font-size: 0.8125rem; }

    & select, & input[type="text"] {
      width: 160px;
      padding: 0.375rem 0.5rem;
      font-size: 0.8125rem;
      border: 1px solid var(--border, #ddd);
      border-radius: 4px;
    }

    & input[type="color"] {
      width: 40px;
      height: 28px;
      border: 1px solid var(--border, #ddd);
      border-radius: 4px;
      cursor: pointer;
      padding: 2px;
    }
  }
}

@media (max-width: 900px) {
  .builder-panes { grid-template-columns: 1fr; }
  .builder-preview { display: none; }
}

/* ── Sub-navigation ── */

.sub-nav {
  display: flex;
  gap: var(--size-2);
  padding-block-end: var(--size-3);
  margin-block-end: var(--size-4);
  border-block-end: 1px solid var(--border);

  & a {
    padding: var(--size-1) var(--size-3);
    border-radius: var(--radius-2);
    font-size: var(--font-size-0);
    color: var(--text-2);
    text-decoration: none;
    transition: background 0.15s;
  }

  & a:hover {
    background: var(--surface-2);
    color: var(--text-1);
  }

  & a[aria-current="page"] {
    background: var(--surface-3);
    color: var(--text-1);
    font-weight: var(--font-weight-6);
  }
}

@media (max-width: 600px) {
  .sub-nav {
    overflow-x: auto;
    flex-wrap: nowrap;
    -webkit-overflow-scrolling: touch;
    scrollbar-width: none;

    & a {
      white-space: nowrap;
      flex-shrink: 0;
    }
  }
}

.badge-draft {
  display: inline-block;
  font-size: 0.6875rem;
  font-weight: 600;
  padding: 0.125rem 0.5rem;
  background: var(--badge-draft-bg, var(--warning-soft));
  color: var(--badge-draft-text, var(--warning-text));
  border-radius: 3px;
  margin-inline-start: 0.5rem;
}

.badge-published {
  display: inline-block;
  font-size: 0.6875rem;
  font-weight: 600;
  padding: 0.125rem 0.5rem;
  background: var(--badge-published-bg, var(--success-soft));
  color: var(--badge-published-text, var(--success-text));
  border-radius: 3px;
}

/* --- Command palette (Ctrl/Cmd-K global search) --- */
.cmdk {
	position: fixed;
	inset: 0;
	z-index: 2000;
	margin: 0;
	width: 100%;
	height: 100%;
	max-width: 100%;
	max-height: 100%;
	border: none;
	padding: 0;
	background: var(--backdrop-cmdk, rgba(0, 0, 0, 0.45));
	display: none;
}
.cmdk[open] { display: block; }
.cmdk-box {
	position: absolute;
	top: 12vh;
	left: 50%;
	transform: translateX(-50%);
	width: min(640px, 92vw);
	background: var(--surface-1, #fff);
	border-radius: 12px;
	box-shadow: var(--shadow-cmdk, 0 20px 60px rgba(0, 0, 0, 0.3));
	overflow: hidden;
}
.cmdk-input {
	width: 100%;
	border: none;
	border-bottom: 1px solid var(--border, #e5e5e5);
	padding: 1rem 1.25rem;
	font-size: 1.05rem;
	background: transparent;
	color: inherit;
	outline: none;
}
.cmdk-results { max-height: 60vh; overflow-y: auto; padding: 0.5rem; }
.cmdk-hint { padding: 1rem 1.25rem; color: var(--text-2, #888); font-size: 0.9rem; margin: 0; }
.cmdk-group-label { padding: 0.5rem 0.85rem 0.25rem; font-size: 0.72rem; text-transform: uppercase; color: var(--text-2, #999); letter-spacing: 0.04em; }
.cmdk-result {
	display: flex;
	align-items: center;
	gap: 0.75rem;
	padding: 0.6rem 0.85rem;
	border-radius: 8px;
	color: inherit;
	text-decoration: none;
}
.cmdk-result:hover, .cmdk-result:focus { background: var(--surface-2, #f4f4f5); outline: none; }
.cmdk-result-type {
	font-size: 0.68rem;
	text-transform: uppercase;
	letter-spacing: 0.03em;
	color: var(--text-2, #999);
	background: var(--surface-3, #eee);
	padding: 0.12rem 0.5rem;
	border-radius: 999px;
	flex-shrink: 0;
}
.cmdk-result-name { flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.cmdk-result-meta { color: var(--text-2, #999); font-size: 0.85rem; flex-shrink: 0; }

/* Support impersonation banner — persistent, high-visibility */
.impersonation-banner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  padding: 0.5rem 1rem;
  background: var(--impersonation-bg, #b45309);
  color: var(--on-accent, #fff);
  font-size: 0.9rem;
  font-weight: 500;
  position: sticky;
  top: 0;
  z-index: 5000;
}
.impersonation-banner span { display: inline-flex; align-items: center; gap: 0.5rem; }
.impersonation-banner strong { font-weight: 700; }
.impersonation-banner button { flex: none; }


/* ── Mobile polish (audited at 390px on every admin page) ───────────────
   Causes confirmed by probing the live DOM, not guessed:
   1. .detail-layout is a grid with a FIXED 442px column, inside a 358px
      parent — every product/order detail card bled off-screen.
   2. Tables inside cards were squeezed below their natural width, so cell
      text collided (analytics ran the customer name into the amount).
   3. The revenue chart scales a 800x200 viewBox down to 356px, clipping
      its y-axis labels to ".000 kr.".
   4. Content sat under the fixed bottom tab bar and the FAB. */
@media (max-width: 600px) {
  /* 1. Detail pages: one fluid column, never a fixed track. */
  .detail-layout {
    grid-template-columns: minmax(0, 1fr) !important;
  }
  .detail-main,
  .detail-sidebar {
    min-width: 0;
    max-width: 100%;
  }

  /* 2. Let card tables take their natural width and scroll horizontally
        instead of squeezing columns until the text overlaps. */
  .dashboard-card,
  section.card {
    & > table,
    & > div > table {
      min-width: max-content;
    }
  }
  table td,
  table th {
    padding-inline: 0.6rem;
    white-space: nowrap;
  }

  /* 3. Give the chart room to render at a legible size; the card scrolls. */
  svg.analytics-chart {
    min-width: 32rem;
  }

  /* 4. Nothing hides under the tab bar or the floating action button. */
  [data-admin] main {
    padding-block-end: 9rem;
  }

  /* Card header actions wrap rather than overflow the card. */
  .card > header,
  .card-header,
  .dashboard-card > header,
  section.card > header {
    flex-wrap: wrap;
    gap: 0.5rem;
  }

  /* Date-range filters stay inside the viewport. */
  .filter-dates,
  .date-range {
    flex-wrap: wrap;
    width: 100%;

    & input { flex: 1 1 8rem; min-width: 0; }
  }
}

/* A log table marked data-stack reads as one small card per row on a phone:
   its cells wrap in a two-column grid instead of the table scrolling sideways
   and hiding the columns that answer the question (an attempt's outcome and
   amount, an audit entry's who and what). Cells may name themselves with
   data-label; the header stays for screen readers. Wide screens are unchanged. */
@media (max-width: 600px) {
  table[data-stack] {
    display: block;
    overflow-x: visible;
    min-width: 0;

    & thead {
      position: absolute;
      width: 1px;
      height: 1px;
      overflow: hidden;
      clip-path: inset(50%);
      white-space: nowrap;
    }

    & tbody {
      display: block;
    }

    & tr {
      display: grid;
      grid-template-columns: repeat(2, minmax(0, 1fr));
      gap: 0.35rem 0.75rem;
      padding: 0.65rem 0.75rem;
      border-block-end: 1px solid var(--surface-3);
    }

    & td {
      display: block;
      min-width: 0;
      padding: 0;
      border: 0;
      white-space: normal;
      overflow-wrap: anywhere;
    }

    & td small {
      display: block;
    }

    & td[data-label]::before {
      content: attr(data-label);
      display: block;
      color: var(--text-2);
      font-size: var(--font-size-0);
    }
  }
}

/* ═══════════════════════════════════════
   Account page (authkit)
   ═══════════════════════════════════════

   Moved out of an inline <style> in the account template: the page is also
   sent over SSE, and a <style> in a morph carries the response's nonce, which
   the page refuses. Scoped to the page, because the storefront's account page
   uses some of the same class names. */
body[data-page="account"] {
  .account-layout {
  	max-width: 680px;
  	margin: 0 auto;
  	padding: 32px 24px;
  }
  .account-section {
  	background: var(--surface-1);
  	border: 1px solid var(--border);
  	border-radius: var(--radius);
  	padding: 20px 24px;
  	margin-bottom: 16px;
  }
  .account-section h2 {
  	font-size: 15px;
  	font-weight: 650;
  	color: var(--text-1);
  	margin-bottom: 16px;
  	letter-spacing: -0.01em;
  }
  .account-header {
  	display: flex;
  	align-items: center;
  	justify-content: space-between;
  	margin-bottom: 28px;
  }
  .account-header h1 {
  	font-size: 20px;
  	font-weight: 700;
  	color: var(--text-1);
  	letter-spacing: -0.02em;
  }
  .account-field {
  	display: flex;
  	align-items: center;
  	justify-content: space-between;
  	padding: 10px 0;
  	border-bottom: 1px solid var(--border);
  }
  .account-field:last-child {
  	border-bottom: none;
  }
  .account-field dt {
  	font-size: 13px;
  	font-weight: 500;
  	color: var(--text-3);
  }
  .account-field dd {
  	font-size: 13px;
  	color: var(--text-1);
  }
  .key-reveal {
  	background: var(--surface-2);
  	border: 1px solid var(--success);
  	border-radius: var(--radius-sm);
  	padding: 12px 16px;
  	margin-bottom: 16px;
  	font-family: var(--font-mono);
  	font-size: 12px;
  	word-break: break-all;
  	color: var(--success-text);
  }
  .key-reveal small {
  	display: block;
  	margin-top: 6px;
  	color: var(--text-3);
  	font-family: var(--font-sans);
  	font-size: 12px;
  }
  .key-item {
  	display: flex;
  	align-items: center;
  	justify-content: space-between;
  	padding: 8px 0;
  	border-bottom: 1px solid var(--border);
  }
  .key-item:last-child { border-bottom: none; }
  .key-name {
  	font-size: 13px;
  	font-weight: 550;
  	color: var(--text-1);
  }
  .key-prefix {
  	font-family: var(--font-mono);
  	font-size: 12px;
  	color: var(--text-3);
  	margin-left: 8px;
  }
  .key-status {
  	font-size: 11px;
  	margin-left: 8px;
  }
  .session-item {
  	display: flex;
  	align-items: center;
  	justify-content: space-between;
  	padding: 8px 0;
  	border-bottom: 1px solid var(--border);
  }
  .session-item:last-child { border-bottom: none; }
  .session-info {
  	font-size: 13px;
  	color: var(--text-2);
  }
  .session-current {
  	font-size: 11px;
  	font-weight: 600;
  	color: var(--success-text);
  }
}

/* The access pages reuse the login card. Their way back to the dashboard is a
   real link that looks like the login button and fills the card like it; the
   way back to the store sits quietly underneath. */
body[data-page="login"] > main > article[aria-labelledby="access-denied-heading"] {
  & > a {
    width: 100%;
    padding: 9px 16px;
    text-decoration: none;
  }
  & > a + button {
    margin-top: 8px;
  }
  & > .access-denied-store {
    margin: 16px 0 0;

    & a {
      color: var(--text-2);
      text-underline-offset: 2px;

      &:hover {
        color: var(--text-1);
      }
    }
  }
}

/* Fetch alert: a refused or lost request shown where the merchant is looking,
   above everything, dismissible; the status code is for the person they call. */
#admin-fetch-alert {
  position: fixed;
  top: 12px;
  left: 12px;
  right: 12px;
  z-index: 9500;
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 10px 10px 10px 14px;
  background: var(--surface-1);
  color: var(--text-1);
  border: 1px solid var(--danger);
  border-left-width: 4px;
  border-radius: var(--radius-sm);
  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.25);
  font-size: 13.5px;
  line-height: 1.4;

  & > p { margin: 0; flex: 1; }
  & code { font-family: var(--font-mono); font-size: 12px; color: var(--danger-text); }
  & code:empty { display: none; }
}
@media (min-width: 768px) {
  #admin-fetch-alert { left: auto; right: 20px; top: 16px; max-width: 460px; }
}

/* A toast's one link: legible on the toast's own colour, reachable on a phone. */
[data-admin] > [role="status"] [role="alert"] a {
  color: inherit;
  font-weight: 650;
  text-decoration: underline;
  text-underline-offset: 2px;
  white-space: nowrap;
}
