/* Vendored from ez2bg-ui-web 1.14.0 by scripts/sync-htmlkit-css.py. Do not edit; edit app.css. */

:root {
    /* Declared per layer rather than once as `light dark`, so that an explicit
       data-theme also flips native form controls, scrollbars and autofill —
       `light dark` only tracks the OS, leaving a forced-dark page with light
       inputs on a light OS. */
    color-scheme: light;

    /* How far up from the bottom edge a floating notice sits: clear of the app's
       fixed bottom nav, whose height every palette emits as --hk-tabbar-h. An app
       with no bottom nav overrides this with a small gap. */
    --hk-toast-bottom: calc(var(--hk-tabbar-h, 80px) + 16px);

    /* Color tokens — light */
    --bg: #f5f5f5;
    --surface: #ffffff;
    --surface2: #f0f3f1;
    --primary: #4CAF50;
    --primary-press: #43a047;
    --secondary: #2196F3;
    --secondary-press: #1976D2;
    --text: #1f2421;
    --text-secondary: #414b45;
    --muted: #5f6963;
    --border: #d0d5d2;
    --divider: #eef1ef;
    --surface-highlight: #e8efe9;
    --overlay: rgba(0,0,0,0.45);
    --danger: #c62828;
    --danger-soft: #fdeaea;
    --ok: #2e7d32;
    --ok-soft: #e8f5e9;
    --warn: #e08600;
    --warn-soft: #fff4e5;

    /* Typography scale */
    --font: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
    --fs-1: 24px;
    --fs-2: 20px;
    --fs-3: 16px;
    --fs-body: 15px;
    --fs-sm: 13px;
    --fs-xs: 12px;

    /* Spacing scale */
    --sp-1: 4px;
    --sp-2: 8px;
    --sp-3: 12px;
    --sp-4: 16px;
    --sp-5: 20px;

    /* Radii */
    --r-sm: 8px;
    --r-md: 11px;
    --r-lg: 14px;
    --r-pill: 999px;

    /* Elevation shadows (Material levels) */
    --shadow-1: 0 1px 3px rgba(0,0,0,0.12), 0 1px 2px rgba(0,0,0,0.08);
    --shadow-2: 0 3px 6px rgba(0,0,0,0.12), 0 2px 4px rgba(0,0,0,0.08);
    --shadow-3: 0 10px 20px rgba(0,0,0,0.12), 0 3px 6px rgba(0,0,0,0.08);
    --shadow-card: var(--shadow-1);

    /* Transitions - Material standard easing */
    --ease-standard: cubic-bezier(0.4, 0, 0.2, 1);
    --ease-decelerate: cubic-bezier(0, 0, 0.2, 1);
    --ease-accelerate: cubic-bezier(0.4, 0, 1, 1);
    --duration-short: 150ms;
    --duration-medium: 250ms;
    --duration-long: 350ms;
}

@media (prefers-color-scheme: dark) {
:root:not([data-theme="light"]) {
    color-scheme: dark;
    --bg: #121212;
    --surface: #1e1e1e;
    --surface2: #262626;
    --surface-highlight: #2f2b3a;
    --overlay: rgba(0,0,0,0.6);
    --primary: #9c7cf4;
    --primary-press: #8a67e8;
    --secondary: #6ba8f4;
    --secondary-press: #5a93e0;
    --text: #f3f0fb;
    --text-secondary: #c8c2d6;
    --muted: #9a93ac;
    --border: #2e2b38;
    --divider: #2e2b38;
    --danger: #ff6b6b;
    --danger-soft: rgba(255,107,107,0.15);
    --ok: #5cd6a0;
    --ok-soft: rgba(92,214,160,0.15);
    --warn: #f5b86b;
    --warn-soft: rgba(245,184,107,0.15);
    --shadow-1: 0 1px 3px rgba(0,0,0,0.3), 0 1px 2px rgba(0,0,0,0.2);
    --shadow-2: 0 3px 6px rgba(0,0,0,0.3), 0 2px 4px rgba(0,0,0,0.2);
    --shadow-3: 0 10px 20px rgba(0,0,0,0.3), 0 3px 6px rgba(0,0,0,0.2);
    --shadow-card: var(--shadow-1);
}
}
:root[data-theme="dark"] {
    color-scheme: dark;
    --bg: #121212;
    --surface: #1e1e1e;
    --surface2: #262626;
    --surface-highlight: #2f2b3a;
    --overlay: rgba(0,0,0,0.6);
    --primary: #9c7cf4;
    --primary-press: #8a67e8;
    --secondary: #6ba8f4;
    --secondary-press: #5a93e0;
    --text: #f3f0fb;
    --text-secondary: #c8c2d6;
    --muted: #9a93ac;
    --border: #2e2b38;
    --divider: #2e2b38;
    --danger: #ff6b6b;
    --danger-soft: rgba(255,107,107,0.15);
    --ok: #5cd6a0;
    --ok-soft: rgba(92,214,160,0.15);
    --warn: #f5b86b;
    --warn-soft: rgba(245,184,107,0.15);
    --shadow-1: 0 1px 3px rgba(0,0,0,0.3), 0 1px 2px rgba(0,0,0,0.2);
    --shadow-2: 0 3px 6px rgba(0,0,0,0.3), 0 2px 4px rgba(0,0,0,0.2);
    --shadow-3: 0 10px 20px rgba(0,0,0,0.3), 0 3px 6px rgba(0,0,0,0.2);
    --shadow-card: var(--shadow-1);
}


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

/* A text-entry control is 16px unless it says otherwise.

   iOS Safari zooms the page whenever a focused control computes under 16px,
   and it does not zoom back out on blur — so one tap on a 14px field leaves
   the whole app scaled up, with the header and its search bar running off the
   right edge, until the user pinches it back. It reads as a layout bug in
   whatever screen they landed on next, which is why it has been "fixed"
   before by correcting the scroll offset: that is the visible half, and
   scrolling cannot undo a scale.

   Deliberately not behind `@media (pointer: coarse)`. 16px is the browser's
   own default for these controls, so there is nothing to win by shrinking
   them on desktop, and a rule that only applies on touch is a rule no
   headless test can see.

   The `:not()` chains are load-bearing, not decoration: they lift each
   selector above a single class, so an app's own `.someInput { font-size:
   14px }` loses to this instead of silently reintroducing the zoom. A control
   that genuinely wants another size opts out by name. */
input:not([type="checkbox"]):not([type="radio"]):not([type="range"]):not([type="color"]):not(.hk-own-font-size),
textarea:not(.hk-own-font-size),
select:not(.hk-own-font-size) { font-size: 16px; }

/* Respect reduced motion preference */
@media (prefers-reduced-motion: reduce) {
    *, *::before, *::after {
        animation-duration: 0.01ms !important;
        animation-iteration-count: 1 !important;
        transition-duration: 0.01ms !important;
    }
}

body {
    font-family: var(--font);
    background: var(--bg);
    color: var(--text);
    min-height: 100vh;
    line-height: 1.5;
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
}

#root { max-width: 680px; margin: 0 auto; padding: var(--sp-4) var(--sp-4) 92px; }

a { color: var(--primary); }

h1 { font-size: var(--fs-1); line-height: 1.2; letter-spacing: -0.5px; font-weight: 700; }
h2 { font-size: var(--fs-2); line-height: 1.3; letter-spacing: -0.25px; font-weight: 600; margin-bottom: var(--sp-3); }
h3 { font-size: var(--fs-3); line-height: 1.4; font-weight: 600; }

.muted { color: var(--muted); font-size: var(--fs-body); }

/* Card */
.hk-card {
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--r-lg);
    padding: 18px;
    margin-bottom: 14px;
    box-shadow: var(--shadow-card);
    transition: border-color 0.2s ease;
}
/* `color-mix`, not `rgba(var(--primary-rgb), …)`.

   These three hover tints wanted a low-opacity wash of the brand colour, and
   `rgba()` cannot take a hex, so they asked for a `--primary-rgb` triplet that
   nothing has ever declared — every app hovered in htmlkit's stock green
   `76,175,80`, whatever its own brand was.

   Declaring the triplet would have worked, but it duplicates `--primary` in a
   second format that can drift from it, and it is uncomputable for an app whose
   `primary` is itself a `var()`. `color-mix` reads `--primary` directly, so
   there is nothing to keep in step and indirection is fine. Where it is
   unsupported the declaration drops and the hover tint is simply absent, which
   is a better failure than painting another brand's colour. */
.hk-card:hover { border-color: color-mix(in srgb, var(--primary) 40%, transparent); }
.hk-card.clickable { cursor: pointer; }
.hk-card.clickable:hover { background: var(--surface2); }

/* Buttons */
.btn {
    background: var(--primary);
    color: var(--on-primary, #fff);
    border: none;
    padding: 14px 18px;
    border-radius: var(--r-md);
    font-size: var(--fs-3);
    font-weight: 700;
    cursor: pointer;
    width: 100%;
    margin-bottom: 10px;
    transition: background var(--duration-short) var(--ease-standard), transform 50ms var(--ease-standard);
}
.btn:hover { background: var(--primary-press); }
.btn:active { transform: scale(0.98); }
.btn:focus-visible { outline: 2px solid var(--primary); outline-offset: 2px; }
.btn:disabled, .btn[disabled] { background: var(--border); color: var(--muted); cursor: not-allowed; opacity: 0.6; }
.btn.loading { position: relative; color: transparent; pointer-events: none; }
.btn.loading::after {
    content: "";
    position: absolute;
    width: 18px;
    height: 18px;
    top: 50%;
    left: 50%;
    margin: -9px 0 0 -9px;
    border: 2px solid var(--on-primary-faint, rgba(255,255,255,0.3));
    border-top-color: var(--on-primary, #fff);
    border-radius: 50%;
    animation: hk-spin 0.8s linear infinite;
}
.hk-photo-picker { display: block; text-align: center; box-sizing: border-box; }
.hk-photo-picker.disabled { background: var(--border); color: var(--muted); cursor: not-allowed; opacity: 0.6; }
.hk-photo-input { display: none; }

.btn-secondary {
    background: var(--surface);
    color: var(--primary);
    border: 2px solid var(--primary);
}
.btn-secondary:hover { background: var(--surface2); }
.btn-secondary:focus-visible { outline-color: var(--primary); }

.btn-ghost {
    background: transparent;
    border: 1px solid var(--border);
    color: var(--text);
    padding: 12px;
    border-radius: var(--r-md);
    cursor: pointer;
    width: 100%;
    margin-bottom: 10px;
    font-size: var(--fs-body);
    font-weight: 600;
}
.btn-ghost:hover { background: var(--surface2); }
.btn-ghost:focus-visible { outline: 2px solid var(--primary); outline-offset: 2px; }

.btn-sm {
    width: auto;
    min-height: 44px;
    padding: 12px 16px;
    font-size: var(--fs-sm);
    margin: 0;
    border-radius: var(--r-sm);
    border: 1px solid var(--border);
    background: var(--surface2);
    color: var(--text);
    cursor: pointer;
    font-weight: 700;
}
.btn-sm:hover { border-color: var(--primary); }
.btn-sm:focus-visible { outline: 2px solid var(--primary); outline-offset: 2px; }
.btn-sm:disabled, .btn-sm[disabled] { opacity: 0.5; cursor: not-allowed; }
/*
 * Two danger treatments, because `.btn` and `.btn-sm` start from opposite
 * backgrounds. Recolouring text alone was written for the pale `.btn-sm` and
 * produced red-on-green on a full-size `.btn` — a kill switch that reads as a
 * confirm button. A destructive control has to look destructive from across
 * the room, not on close inspection.
 */
.btn-sm.btn-danger { color: var(--danger); border-color: var(--danger); }
.btn.btn-danger {
    background: var(--danger);
    color: var(--on-danger, #fff);
    border-color: var(--danger);
}
.btn.btn-danger:hover { filter: brightness(0.92); }
.btn.btn-danger:focus-visible { outline: 2px solid var(--danger); outline-offset: 2px; }

/* Inputs */
.inp, .hk-input, textarea.inp, textarea.hk-input {
    width: 100%;
    min-height: 44px;
    padding: 13px 14px;
    font-size: var(--fs-3);
    border: 1px solid var(--border);
    border-radius: var(--r-md);
    margin-bottom: 12px;
    background: var(--surface);
    color: var(--text);
    font-family: inherit;
}
.inp:focus, .hk-input:focus, textarea.inp:focus, textarea.hk-input:focus { outline: none; border-color: var(--primary); box-shadow: 0 0 0 3px color-mix(in srgb, var(--primary) 12%, transparent); }
.inp:disabled, .hk-input:disabled, textarea.inp:disabled, textarea.hk-input:disabled { background: var(--surface2); color: var(--muted); cursor: not-allowed; opacity: 0.7; }
.inp.error, .hk-input.error { border-color: var(--danger); }
/* The same split the brand focus ring had: the `border-color` above reads
   `var(--danger)` while this ring hardcoded the *light* danger red, so in dark
   mode an invalid field was outlined in one red and haloed in another. */
.inp.error:focus, .hk-input.error:focus { box-shadow: 0 0 0 3px color-mix(in srgb, var(--danger) 12%, transparent); }
textarea.inp, textarea.hk-input { resize: vertical; min-height: 90px; }
label.fld { display: block; font-size: var(--fs-sm); color: var(--text); margin-bottom: 6px; font-weight: 600; }
.field-error { color: var(--danger); font-size: var(--fs-sm); margin-top: -8px; margin-bottom: 12px; }

/* Layout helpers */
.row { display: flex; gap: 10px; align-items: center; }
.row > * { flex: 1; }
.grow { flex: 1; min-width: 0; }
.wrap { display: flex; flex-wrap: wrap; gap: 8px; margin-bottom: 12px; }

/* Chips */
.chip {
    display: inline-flex;
    align-items: center;
    min-height: 44px;
    padding: 10px 16px;
    border-radius: var(--r-pill);
    font-size: var(--fs-sm);
    font-weight: 700;
    background: var(--surface2);
    color: var(--text);
    border: 1px solid var(--border);
    cursor: pointer;
    transition: border-color 0.15s ease, background 0.15s ease;
}
.chip:hover { border-color: var(--primary); background: color-mix(in srgb, var(--primary) 8%, transparent); }
.chip:focus-visible { outline: 2px solid var(--primary); outline-offset: 2px; }
.chip.sel { background: var(--primary); color: var(--on-primary, #fff); border-color: var(--primary); }
.chip-crit { background: var(--danger-soft); color: var(--danger); }
.chip-soon { background: var(--warn-soft); color: var(--warn); }
.chip-ok   { background: var(--ok-soft); color: var(--ok); }

/* Chip rail — one row of chips that scrolls sideways (see ChipRail).
   Distinct from .wrap, which grows downward: inside a dialog that costs the
   list below it, so the rail trades vertical growth for a horizontal scroll.
   `flex-shrink: 0` on the children is load-bearing — a flex child's default
   `min-width: auto` lets long community names squeeze each other into
   ellipsis instead of overflowing, and then there is nothing to scroll. */
.hk-chip-rail {
    display: flex;
    gap: 8px;
    margin-bottom: 12px;
    overflow-x: auto;
    overflow-y: hidden;
    scroll-snap-type: x proximity;
    -webkit-overflow-scrolling: touch;
    scrollbar-width: none;
}
.hk-chip-rail::-webkit-scrollbar { display: none; }
.hk-chip-rail > .chip { flex: 0 0 auto; scroll-snap-align: start; white-space: nowrap; }

/* Radio group — stacked single-choice list (see RadioGroup).
   Distinct from .chip, which is a horizontal filter strip: these are full
   width rows with room for a real radio control, not pills. */
.hk-radio-group { display: flex; flex-direction: column; gap: 8px; margin-bottom: 12px; }
.hk-radio {
    display: flex;
    align-items: center;
    gap: 10px;
    min-height: 44px;
    padding: 10px 14px;
    box-sizing: border-box;
    border-radius: var(--r-md);
    font-size: var(--fs-sm);
    background: var(--surface);
    color: var(--text);
    border: 1px solid var(--border);
    cursor: pointer;
    transition: border-color 0.15s ease, background 0.15s ease;
}
.hk-radio:hover { border-color: var(--primary); background: color-mix(in srgb, var(--primary) 8%, transparent); }
/* focus-within, not focus-visible: the focusable element is the nested input,
   but the ring belongs on the row the user sees. */
.hk-radio:focus-within { outline: 2px solid var(--primary); outline-offset: 2px; }
/* Ring rather than a solid primary fill — unlike a chip, this row contains a
   radio control that has to stay legible against its background. */
.hk-radio.sel {
    border-color: var(--primary);
    box-shadow: inset 0 0 0 1px var(--primary);
    font-weight: 600;
}
.hk-radio input { margin: 0; accent-color: var(--primary); flex: none; }

/* Pills (status) */
.pill { padding: 3px 10px; border-radius: var(--r-pill); font-size: var(--fs-xs); font-weight: 800; }
.pill-ok { background: var(--ok-soft); color: var(--ok); }
.pill-warn { background: var(--warn-soft); color: var(--warn); }
.pill-muted { background: var(--surface2); color: var(--muted); }

/* List items */
.hk-list-item {
    display: flex;
    align-items: center;
    gap: 12px;
    min-height: 48px;
    padding: var(--sp-3) var(--sp-2);
    border-bottom: 1px solid var(--divider);
}
.hk-list-item:last-child { border-bottom: none; }
.hk-list-item:focus-visible { outline: 2px solid var(--primary); outline-offset: -2px; }
.hk-list-item.clickable { cursor: pointer; }
.hk-list-item.clickable:hover { background: var(--surface2); }
.name { font-weight: 700; font-size: var(--fs-body); }

/* Avatar */
.avatar {
    width: 46px;
    height: 46px;
    border-radius: 50%;
    object-fit: cover;
    background: var(--surface2);
    flex-shrink: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    font-weight: 800;
    color: var(--primary);
}

/* Nav bar */
.navbar {
    position: fixed;
    bottom: 0;
    left: 0;
    right: 0;
    background: var(--surface);
    border-top: 1px solid var(--border);
    display: flex;
    justify-content: space-around;
    padding: 8px 4px calc(8px + env(safe-area-inset-bottom));
    z-index: 100;
}
.navbar a {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 2px;
    font-size: var(--fs-xs);
    color: var(--muted);
    text-decoration: none;
    padding: var(--sp-2) var(--sp-3);
    min-height: 48px;
    min-width: 48px;
    flex: 1;
    font-weight: 600;
}
.navbar a:hover { color: var(--text); }
.navbar a:focus-visible { outline: 2px solid var(--primary); outline-offset: -2px; }
.navbar a .ico { font-size: 20px; }
.navbar a.active { color: var(--primary); }

/* Feedback */
.err { color: var(--danger); margin-bottom: 10px; font-size: var(--fs-body); }
.err.err-dismissible {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--sp-2);
    padding: var(--sp-2) var(--sp-3);
    background: rgba(220, 53, 69, 0.08);
    border: 1px solid rgba(220, 53, 69, 0.25);
    border-radius: 4px;
}
.err-dismissible-msg { flex: 1; }
.err-dismiss-btn {
    all: unset;
    cursor: pointer;
    padding: 0 var(--sp-2);
    font-size: 1.25rem;
    line-height: 1;
    color: inherit;
    opacity: 0.7;
    transition: opacity 120ms ease;
}
.err-dismiss-btn:hover { opacity: 1; }
.err-dismiss-btn:focus-visible { outline: 2px solid currentColor; outline-offset: 2px; }
.ok { color: var(--ok); }
.center { display: flex; align-items: center; justify-content: center; min-height: 70vh; flex-direction: column; gap: 14px; }
.spinner {
    width: 38px;
    height: 38px;
    border: 3px solid var(--border);
    border-radius: 50%;
    border-top-color: var(--primary);
    animation: hk-spin 0.9s linear infinite;
}
@keyframes hk-spin { to { transform: rotate(360deg); } }

/* Toggle button */
.toggle {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    cursor: pointer;
    min-height: 44px;
    padding: 12px 16px;
    border-radius: var(--r-sm);
    font-size: var(--fs-sm);
    text-align: center;
    border: 1px solid var(--border);
    background: var(--surface);
    font-weight: 600;
    transition: background 0.12s ease, border-color 0.12s ease;
}
.toggle:hover { border-color: var(--primary); }
.toggle:focus-visible { outline: 2px solid var(--primary); outline-offset: 2px; }
/* The selected/focused states below name `--primary` like the `:hover` and
   `:focus-visible` rules directly above them. They used to spell the same
   intent as literals — `rgba(76,175,80,…)` and `#4caf50`, htmlkit's stock
   green — so a selected toggle, a chosen option and a focused input were green
   in every app whatever its brand, sitting next to a hover border that was not.
   A literal is invisible to `check-css-tokens.sh`, which looks for tokens that
   are read and never declared, not for values that should have been tokens. */
.toggle-on {
    background: color-mix(in srgb, var(--primary) 25%, transparent);
    border-color: var(--primary);
}

/* Option button (for option groups) */
.option-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    cursor: pointer;
    min-height: 44px;
    padding: 12px 16px;
    border-radius: var(--r-sm);
    font-size: var(--fs-sm);
    text-align: center;
    border: 1px solid var(--border);
    background: var(--surface);
    font-weight: 600;
    transition: background 0.12s ease, border-color 0.12s ease;
}
.option-btn:hover { border-color: var(--primary); }
.option-btn:focus-visible { outline: 2px solid var(--primary); outline-offset: 2px; }
.option-btn-sel {
    background: color-mix(in srgb, var(--primary) 25%, transparent);
    border-color: var(--primary);
}

/* Form groups */
.hk-form-group { margin-bottom: var(--sp-4); }
.hk-form-label {
    display: block;
    font-size: var(--fs-sm);
    font-weight: 600;
    color: var(--text);
    margin-bottom: var(--sp-1);
}

/* Sheet / Modal */
.hk-overlay {
    position: fixed;
    top: 0; left: 0; right: 0; bottom: 0;
    background: rgba(0,0,0,0.5);
    z-index: 1050;
}
/* A <dialog>, so it sits in the top layer and is positioned against the
   viewport whatever it happens to be nested inside. Everything from `margin`
   down undoes a UA default that would otherwise centre it, cap it at
   `calc(100% - 6px - 2em)`, or paint a border and a Canvas-coloured background
   over the theme. */
.hk-sheet {
    position: fixed;
    inset: auto 0 0 0;
    margin: 0;
    padding: 0 0 env(safe-area-inset-bottom, 20px) 0;
    border: none;
    width: 100%;
    max-width: 100%;
    background: var(--surface);
    color: var(--text);
    border-radius: var(--r-lg) var(--r-lg) 0 0;
    max-height: 85vh;
}
/* Scoped to [open] because the UA sheet hides a closed dialog with
   `display: none`, and an unconditional `display: flex` here would beat it and
   leave a dismissed sheet on screen. */
.hk-sheet[open] {
    display: flex;
    flex-direction: column;
    animation: hk-slide-up 0.25s ease-out;
}
.hk-sheet::backdrop { background: rgba(0,0,0,0.5); }
@keyframes hk-slide-up {
    from { transform: translateY(100%); }
    to { transform: translateY(0); }
}
.hk-sheet-header {
    display: flex;
    justify-content: space-between;
    align-items: center;
    padding: var(--sp-4);
    border-bottom: 1px solid var(--border);
    flex-shrink: 0;
}
.hk-sheet-close {
    background: transparent;
    border: none;
    font-size: 20px;
    color: var(--muted);
    cursor: pointer;
    padding: var(--sp-2);
    min-width: 44px;
    min-height: 44px;
    display: flex;
    align-items: center;
    justify-content: center;
    border-radius: var(--r-sm);
}
.hk-sheet-close:hover { background: var(--surface2); color: var(--text); }
.hk-sheet-close:focus-visible { outline: 2px solid var(--primary); outline-offset: 2px; }
/* `flex: 1 1 auto`, never `flex: 1`.

   `flex: 1` expands to `flex: 1 1 0%`, and a *percentage* flex-basis has to
   resolve against the container's main size — which is indefinite here, because
   the sheet is sized by its content under a `max-height` with no `height`.
   Chrome falls back to content-based sizing and looks correct; Safari resolves
   the percentage to 0, so the rows collapse to nothing and the sheet renders as
   its header and close button alone. `auto` takes the basis from the content in
   both engines.

   `min-height: 0` is belt-and-braces, and the honest note is that it changes
   nothing in Chrome: a flex item's automatic minimum size is only its content
   while `overflow` is `visible`, and this item scrolls — so `overflow: auto` has
   already zeroed it. Deleting the line keeps every test green. It is here
   because Safari is the engine this whole declaration exists for and has a
   history of not applying that exemption, and because it makes the `overflow`
   declaration's second job explicit: changing `overflow` back to `visible`
   would otherwise silently pin the body open at its content height. */
.hk-sheet-content {
    padding: var(--sp-4);
    overflow: auto;
    flex: 1 1 auto;
    min-height: 0;
    -webkit-overflow-scrolling: touch;
}

/* Game rules: the sheet's inner layout and the host's Rules button. */
.hk-rules { display: flex; flex-direction: column; gap: 10px; }
.hk-rules-summary { margin: 0; font-weight: 600; }
.hk-rules h4 { margin: 8px 0 0; font-size: 0.95rem; }
.hk-rules ul { margin: 0; padding-left: 20px; display: flex; flex-direction: column; gap: 6px; }
.hk-rules-host { position: relative; }
.hk-rules-button {
  position: absolute; top: 8px; right: 8px; z-index: 2;
  padding: 4px 10px; border-radius: 999px; border: 1px solid var(--border);
  background: var(--surface); color: var(--text); font-size: 0.8rem; cursor: pointer;
}

/* Pill variants */
.pill-error { background: var(--danger-soft); color: var(--danger); }

/* Empty state */
.hk-empty {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    padding: var(--sp-5);
    text-align: center;
    gap: var(--sp-3);
    min-height: 200px;
}
.hk-empty-icon { font-size: 48px; }
.hk-empty-action { margin-top: var(--sp-3); }

/* Action item (for action sheets / menus) */
.hk-action-item {
    display: flex;
    align-items: center;
    gap: var(--sp-4);
    padding: var(--sp-4);
    min-height: 48px;
    cursor: pointer;
    border-radius: var(--r-sm);
    transition: background 0.15s ease;
}
.hk-action-item:hover { background: var(--surface2); }
.hk-action-item:focus-visible { outline: 2px solid var(--primary); outline-offset: -2px; }
.hk-action-item-disabled { cursor: default; opacity: 0.45; }
.hk-action-item-disabled:hover { background: none; }
.hk-action-icon {
    width: 48px;
    height: 48px;
    border-radius: 10px;
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 24px;
    background: var(--primary);
    flex-shrink: 0;
    box-shadow: inset 0 0 0 2px rgba(0,0,0,0.08);
}
.hk-action-title {
    display: block;
    font-size: var(--fs-3);
    font-weight: 600;
    color: var(--text);
}
.hk-action-subtitle {
    display: block;
    font-size: var(--fs-sm);
    color: var(--muted);
}
.hk-action-arrow { color: var(--muted); }

/* Touch helpers - minimum 48px targets */
.touch-target { min-height: 48px; min-width: 48px; }
.touch-manipulation { touch-action: manipulation; -webkit-tap-highlight-color: transparent; }

/* Page layout */
.hk-page { min-height: 100vh; display: flex; flex-direction: column; }
.hk-nav {
    display: flex;
    justify-content: space-between;
    align-items: center;
    padding: var(--sp-3) var(--sp-4);
    background: var(--surface);
    border-bottom: 1px solid var(--border);
    position: sticky;
    top: 0;
    z-index: 50;
}
.hk-nav-title {
    font-size: var(--fs-2);
    font-weight: 700;
    cursor: pointer;
    color: var(--primary);
}
.hk-content { flex: 1; padding: var(--sp-4); }

/* Section headers */
.section-header {
    font-size: var(--fs-sm);
    font-weight: 700;
    color: var(--muted);
    text-transform: uppercase;
    letter-spacing: 0.5px;
    margin-bottom: var(--sp-3);
}

/* Tab bar */
.hk-tabs {
    display: flex;
    gap: var(--sp-1);
    margin-bottom: var(--sp-4);
    border-bottom: 1px solid var(--border);
}
.hk-tab {
    padding: var(--sp-3) var(--sp-4);
    min-height: 48px;
    font-size: var(--fs-body);
    font-weight: 600;
    color: var(--muted);
    cursor: pointer;
    border-bottom: 2px solid transparent;
    transition: color 0.15s, border-color 0.15s;
    display: flex;
    align-items: center;
}
.hk-tab:hover { color: var(--text); }
.hk-tab:focus-visible { outline: 2px solid var(--primary); outline-offset: -2px; }
.hk-tab.active { color: var(--primary); border-bottom-color: var(--primary); }

/* Alerts */
.hk-alert {
    display: flex;
    justify-content: space-between;
    align-items: center;
    padding: var(--sp-3) var(--sp-4);
    border-radius: var(--r-md);
    margin-bottom: var(--sp-3);
    font-size: var(--fs-body);
}
.hk-alert-success { background: var(--ok-soft); color: var(--ok); }
.hk-alert-error { background: var(--danger-soft); color: var(--danger); }
.hk-alert-warn { background: var(--warn-soft); color: var(--warn); }
.hk-alert-info { background: var(--surface2); color: var(--text); }
.hk-alert-close {
    background: transparent;
    border: none;
    font-size: 18px;
    cursor: pointer;
    color: inherit;
    opacity: 0.7;
    min-width: 44px;
    min-height: 44px;
    display: flex;
    align-items: center;
    justify-content: center;
    border-radius: var(--r-sm);
    margin: calc(-1 * var(--sp-2)) calc(-1 * var(--sp-2)) calc(-1 * var(--sp-2)) 0;
}
.hk-alert-close:hover { opacity: 1; background: rgba(0,0,0,0.1); }
.hk-alert-close:focus-visible { outline: 2px solid currentColor; outline-offset: -2px; }

/* Progress bar */
.hk-progress-wrap { margin-bottom: var(--sp-3); }
.hk-progress-header {
    display: flex;
    justify-content: space-between;
    margin-bottom: var(--sp-1);
    font-size: var(--fs-sm);
}
.hk-progress-label { color: var(--muted); }
.hk-progress-pct { color: var(--text); font-weight: 600; }
.hk-progress-track {
    height: 8px;
    background: var(--surface2);
    border-radius: 4px;
    overflow: hidden;
}
.hk-progress-fill {
    height: 100%;
    background: var(--primary);
    border-radius: 4px;
    transition: width 0.3s ease;
}
.hk-progress-fill.hk-progress-ok { background: var(--ok); }
.hk-progress-fill.hk-progress-warn { background: var(--warn); }
.hk-progress-fill.hk-progress-error { background: var(--danger); }
.hk-progress-fill.hk-progress-muted { background: var(--muted); }

/* Back link */
.hk-back {
    color: var(--primary);
    text-decoration: none;
    font-size: var(--fs-body);
    display: inline-flex;
    align-items: center;
    min-height: 44px;
    padding: var(--sp-2) var(--sp-1);
    margin-bottom: var(--sp-4);
    border-radius: var(--r-sm);
}
.hk-back:hover { text-decoration: underline; }
.hk-back:focus-visible { outline: 2px solid var(--primary); outline-offset: 2px; }

/* Page header */
.hk-page-header { margin-bottom: var(--sp-5); }
.hk-page-header h1 {
    font-size: var(--fs-1);
    margin: 0 0 var(--sp-2) 0;
}

/* Checkbox */
.hk-checkbox {
    display: flex;
    align-items: center;
    gap: var(--sp-2);
    cursor: pointer;
    font-size: var(--fs-body);
    color: var(--text);
    min-height: 44px;
    padding: var(--sp-1) 0;
}
.hk-checkbox:focus-visible { outline: 2px solid var(--primary); outline-offset: 2px; border-radius: var(--r-sm); }
.hk-check-box {
    width: 20px;
    height: 20px;
    border: 2px solid var(--border);
    border-radius: 4px;
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 14px;
    color: transparent;
    transition: all 0.15s ease;
    flex-shrink: 0;
}
.hk-check-box.checked {
    background: var(--primary);
    border-color: var(--primary);
    color: var(--on-primary, #fff);
}

/* Switch */
.hk-switch-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    cursor: pointer;
    padding: var(--sp-2) 0;
    min-height: 44px;
}
.hk-switch-row:focus-visible { outline: 2px solid var(--primary); outline-offset: 2px; border-radius: var(--r-sm); }
.hk-switch-label { color: var(--text); font-size: var(--fs-body); }
.hk-switch {
    width: 44px;
    height: 24px;
    background: var(--border);
    border-radius: 12px;
    position: relative;
    transition: background 0.2s ease;
    flex-shrink: 0;
}
.hk-switch.on { background: var(--primary); }
.hk-switch-thumb {
    position: absolute;
    top: 2px;
    left: 2px;
    width: 20px;
    height: 20px;
    background: #fff;
    border-radius: 50%;
    transition: left 0.2s ease;
    box-shadow: 0 1px 3px rgba(0,0,0,0.2);
}
.hk-switch.on .hk-switch-thumb { left: 22px; }

/* Search input */
.hk-search {
    display: flex;
    align-items: center;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--r-md);
    padding: 0 var(--sp-3);
    gap: var(--sp-2);
}
.hk-search:focus-within { border-color: var(--primary); }
.hk-search-icon { color: var(--muted); font-size: 14px; }
.hk-search-input {
    flex: 1;
    border: none;
    background: transparent;
    padding: var(--sp-3) 0;
    font-size: var(--fs-body);
    color: var(--text);
    outline: none;
}
.hk-search-clear {
    background: transparent;
    border: none;
    color: var(--muted);
    font-size: 18px;
    cursor: pointer;
    padding: var(--sp-2);
    min-width: 44px;
    min-height: 44px;
    display: flex;
    align-items: center;
    justify-content: center;
    margin-right: calc(-1 * var(--sp-2));
    border-radius: var(--r-sm);
}
.hk-search-clear:hover { color: var(--text); background: var(--surface2); }
.hk-search-clear:focus-visible { outline: 2px solid var(--primary); outline-offset: -2px; }

/* Divider */
.hk-divider {
    border: none;
    border-top: 1px solid var(--border);
    margin: var(--sp-4) 0;
}
.hk-divider-label {
    display: flex;
    align-items: center;
    gap: var(--sp-3);
    margin: var(--sp-4) 0;
    color: var(--muted);
    font-size: var(--fs-sm);
}
.hk-divider-label hr { flex: 1; }

/* Icon button */
.hk-icon-btn {
    width: 48px;
    height: 48px;
    border-radius: 50%;
    border: 1px solid var(--border);
    background: var(--surface);
    color: var(--text);
    font-size: 18px;
    cursor: pointer;
    display: flex;
    align-items: center;
    justify-content: center;
    transition: all 0.15s ease;
}
.hk-icon-btn:hover { border-color: var(--primary); background: var(--surface2); }
.hk-icon-btn:focus-visible { outline: 2px solid var(--primary); outline-offset: 2px; }
.hk-icon-btn.danger { color: var(--danger); border-color: var(--danger); }
.hk-icon-btn.danger:hover { background: var(--danger-soft); }
.hk-icon-btn.ghost { border: none; background: transparent; }
.hk-icon-btn.ghost:hover { background: var(--surface2); }

/* Link button */
.hk-link-btn {
    background: transparent;
    border: none;
    color: var(--primary);
    font-size: var(--fs-body);
    cursor: pointer;
    padding: var(--sp-2) var(--sp-1);
    min-height: 44px;
    display: inline-flex;
    align-items: center;
    text-decoration: underline;
}
.hk-link-btn:hover { opacity: 0.8; }
.hk-link-btn:focus-visible { outline: 2px solid var(--primary); outline-offset: 2px; }

/* Grid */
.hk-grid {
    display: grid;
    grid-template-columns: repeat(var(--grid-cols, 2), 1fr);
}
@media (max-width: 600px) {
    .hk-grid { grid-template-columns: 1fr; }
}

/* Skeleton */
.hk-skeleton {
    background: linear-gradient(90deg, var(--surface2) 25%, var(--surface) 50%, var(--surface2) 75%);
    background-size: 200% 100%;
    animation: hk-shimmer 1.5s infinite;
    border-radius: 4px;
}
.hk-skeleton.rounded { border-radius: 50%; }
@keyframes hk-shimmer {
    0% { background-position: 200% 0; }
    100% { background-position: -200% 0; }
}
.hk-skeleton-text {
    display: flex;
    flex-direction: column;
    gap: var(--sp-2);
}

/* Badge */
.hk-badge {
    display: inline-block;
    padding: 2px 8px;
    border-radius: var(--r-pill);
    font-size: var(--fs-xs);
    font-weight: 600;
    background: var(--badge-color, var(--primary));
    color: var(--on-badge, var(--on-primary, #fff));
}

/* Confirmation Dialog */
.hk-dialog {
    position: fixed;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    background: var(--surface);
    border-radius: var(--r-lg);
    padding: var(--sp-5);
    min-width: 300px;
    max-width: 90vw;
    z-index: 1200;
    box-shadow: 0 10px 40px rgba(0,0,0,0.3);
    animation: hk-dialog-in 0.2s ease-out;
}
@keyframes hk-dialog-in {
    from { opacity: 0; transform: translate(-50%, -50%) scale(0.95); }
    to { opacity: 1; transform: translate(-50%, -50%) scale(1); }
}
.hk-dialog-title {
    margin: 0 0 var(--sp-3) 0;
    font-size: var(--fs-2);
    color: var(--text);
}
.hk-dialog-message {
    margin: 0 0 var(--sp-4) 0;
    color: var(--muted);
    font-size: var(--fs-body);
    line-height: 1.5;
}
.hk-dialog-actions {
    display: flex;
    gap: var(--sp-3);
    justify-content: flex-end;
}
.hk-dialog-btn {
    padding: var(--sp-3) var(--sp-4);
    min-height: 44px;
    border-radius: var(--r-md);
    font-size: var(--fs-body);
    font-weight: 600;
    cursor: pointer;
    border: none;
    transition: background 0.15s ease;
}
.hk-dialog-btn:focus-visible { outline: 2px solid var(--primary); outline-offset: 2px; }
.hk-dialog-btn.cancel {
    background: var(--surface2);
    color: var(--text);
}
.hk-dialog-btn.cancel:hover { background: var(--border); }
.hk-dialog-btn.confirm {
    background: var(--primary);
    color: var(--on-primary, #fff);
}
.hk-dialog-btn.confirm:hover { background: var(--primary-press); }
.hk-dialog-btn.confirm:focus-visible { outline-color: var(--text); }
.hk-dialog-btn.confirm.danger {
    background: var(--danger);
    color: var(--on-danger, #fff);
}
.hk-dialog-btn.confirm.danger:hover { opacity: 0.9; }

/* Toast / Snackbar */
.hk-toast-container {
    position: fixed;
    bottom: var(--sp-4);
    right: var(--sp-4);
    display: flex;
    flex-direction: column;
    gap: var(--sp-2);
    z-index: 1300;
    max-width: 400px;
}
@media (max-width: 500px) {
    .hk-toast-container {
        left: var(--sp-4);
        right: var(--sp-4);
        max-width: none;
    }
}
.hk-toast {
    display: flex;
    align-items: center;
    gap: var(--sp-3);
    padding: var(--sp-3) var(--sp-4);
    border-radius: var(--r-md);
    background: var(--surface);
    border: 1px solid var(--border);
    box-shadow: 0 4px 12px rgba(0,0,0,0.15);
    animation: hk-toast-in 0.3s ease-out;
}
@keyframes hk-toast-in {
    from { opacity: 0; transform: translateX(100%); }
    to { opacity: 1; transform: translateX(0); }
}
.hk-toast.success { border-left: 4px solid var(--ok); }
.hk-toast.error { border-left: 4px solid var(--danger); }
.hk-toast.warn { border-left: 4px solid var(--warn); }
.hk-toast.info { border-left: 4px solid var(--primary); }
.hk-toast-message {
    flex: 1;
    color: var(--text);
    font-size: var(--fs-body);
}
.hk-toast-close {
    background: transparent;
    border: none;
    color: var(--muted);
    font-size: 18px;
    cursor: pointer;
    min-width: 44px;
    min-height: 44px;
    display: flex;
    align-items: center;
    justify-content: center;
    margin: calc(-1 * var(--sp-2)) calc(-1 * var(--sp-2)) calc(-1 * var(--sp-2)) 0;
    border-radius: var(--r-sm);
}
.hk-toast-close:hover { color: var(--text); background: var(--surface2); }
.hk-toast-close:focus-visible { outline: 2px solid var(--primary); outline-offset: -2px; }

/* Dropdown Menu */
.hk-dropdown {
    position: relative;
    display: inline-block;
}
.hk-dropdown-trigger {
    display: flex;
    align-items: center;
    gap: var(--sp-2);
    padding: var(--sp-3) var(--sp-4);
    min-height: 44px;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--r-md);
    color: var(--text);
    font-size: var(--fs-body);
    cursor: pointer;
}
.hk-dropdown-trigger:hover { border-color: var(--primary); }
.hk-dropdown-trigger:focus-visible { outline: 2px solid var(--primary); outline-offset: 2px; }
.hk-dropdown-arrow {
    font-size: 10px;
    color: var(--muted);
}
.hk-dropdown-menu {
    position: absolute;
    top: 100%;
    right: 0;
    margin-top: var(--sp-1);
    min-width: 160px;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--r-md);
    box-shadow: 0 4px 12px rgba(0,0,0,0.15);
    z-index: 1100;
    overflow: hidden;
    animation: hk-dropdown-in 0.15s ease-out;
}
@keyframes hk-dropdown-in {
    from { opacity: 0; transform: translateY(-8px); }
    to { opacity: 1; transform: translateY(0); }
}
.hk-dropdown-item {
    display: flex;
    align-items: center;
    gap: var(--sp-2);
    padding: var(--sp-3) var(--sp-4);
    min-height: 48px;
    color: var(--text);
    font-size: var(--fs-body);
    cursor: pointer;
    transition: background 0.1s ease;
}
.hk-dropdown-item:hover { background: var(--surface2); }
.hk-dropdown-item:focus-visible { background: var(--surface2); outline: none; }
.hk-dropdown-item.danger { color: var(--danger); }
.hk-dropdown-item.danger:hover { background: var(--danger-soft); }
.hk-dropdown-icon { font-size: 16px; }
.hk-dropdown-backdrop {
    position: fixed;
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
    z-index: 1050;
}

/* ---------- DataTable ---------- */
/* Operator tables: dense, scrollable on narrow viewports, and token-only so a
   row highlight follows the scheme instead of baking a light-mode tint. */
.hk-table-wrap { overflow-x: auto; }
.hk-table { width: 100%; border-collapse: collapse; font-size: var(--fs-body); }
.hk-table th, .hk-table td {
    text-align: left;
    padding: var(--sp-2) var(--sp-3);
    border-bottom: 1px solid var(--border);
    vertical-align: top;
    white-space: nowrap;
}
.hk-table td.wrap { white-space: normal; word-break: break-word; }
.hk-table th {
    color: var(--muted);
    font-weight: 600;
    font-size: 12px;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    position: sticky;
    top: 0;
    background: var(--bg);
}
.hk-table th.sortable { cursor: pointer; user-select: none; }
.hk-table th.sortable:hover { color: var(--text); }
.hk-table th .hk-sort-caret { margin-left: 4px; opacity: 0.7; }
.hk-table tbody tr:hover { background: var(--surface2); }
.hk-table .hk-td-mono { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: 12px; }

/* Paste-time link cleaning notice. Sits directly under the field it belongs to,
   so `margin-top: -8px` cancels the `.inp` bottom margin and the two read as one
   control. Colours come from the ok/ok-soft token pair, which is defined in both
   schemes — a hardcoded green here is the split that put an invalid field's
   border in one red and its focus ring in another. */
.hk-linkclean {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: 8px;
    margin-top: -8px;
    margin-bottom: 12px;
    padding: 8px 10px;
    border: 1px solid color-mix(in srgb, var(--ok) 35%, transparent);
    border-radius: var(--r-md);
    background: var(--ok-soft);
    font-size: var(--fs-sm);
    line-height: 1.4;
}
.hk-linkclean__text { flex: 1 1 180px; min-width: 0; color: var(--text); }
.hk-linkclean__lead { font-weight: 600; }
/* The param names are the evidence, so they are monospaced and allowed to wrap
   rather than truncated — a name cut to `utm_sou…` proves nothing. */
.hk-linkclean__names {
    font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
    color: var(--text-secondary);
    overflow-wrap: anywhere;
}
.hk-linkclean__actions { display: flex; gap: 6px; flex: 0 0 auto; }
.hk-linkclean__btn {
    cursor: pointer;
    user-select: none;
    padding: 6px 10px;
    min-height: 32px;
    display: inline-flex;
    align-items: center;
    border: 1px solid var(--border);
    border-radius: var(--r-sm);
    background: var(--surface);
    color: var(--text);
    font-size: var(--fs-sm);
    font-weight: 600;
}
.hk-linkclean__btn:hover { background: var(--surface2); }
/* The "Change" affordance is the least urgent of the three — it leads somewhere
   rather than deciding anything — so it reads as a link beside two buttons. */
.hk-linkclean__btn.is-quiet {
    background: transparent;
    border-color: transparent;
    color: var(--text-secondary);
    text-decoration: underline;
}
.hk-linkclean__btn.is-quiet:hover { background: transparent; color: var(--text); }
.hk-linkclean__btn:focus-visible { outline: 2px solid var(--primary); outline-offset: 2px; }
.hk-linkclean__btn.is-primary {
    background: var(--primary);
    border-color: var(--primary);
    color: var(--on-primary, #fff);
}
.hk-linkclean__btn.is-primary:hover { filter: brightness(0.94); }

/* App-wide paste-clean notice. Anchored to the bottom of the viewport because the
   field it belongs to can be anywhere, including inside a scrolled sheet.

   The bottom offset comes from `--hk-toast-bottom`, declared above in terms of
   `--hk-tabbar-h` — a hardcoded offset put this notice *underneath* goodnabe's
   80px tab bar, where its buttons cannot be tapped at all.
   `env(safe-area-inset-bottom)` keeps it clear of the iOS home indicator, where
   a notice under the gesture bar has its buttons swallowed by the swipe.

   `--z-toast` rather than a literal: a field can live inside a modal, and a
   notice behind the modal it belongs to is a notice nobody sees. */
.hk-linkclean-toast {
    position: fixed;
    left: 50%;
    transform: translateX(-50%);
    bottom: calc(var(--hk-toast-bottom) + env(safe-area-inset-bottom, 0px));
    z-index: var(--z-toast, 1200);
    width: min(560px, calc(100vw - 32px));
    box-sizing: border-box;
}
/* The notice styles assume they sit under a field, where they cancel the input's
   bottom margin. Floating, they own their own box and get a shadow so they read as
   above the page rather than part of it. */
.hk-linkclean-toast > .hk-linkclean {
    margin: 0;
    background: var(--surface);
    border-color: color-mix(in srgb, var(--ok) 55%, transparent);
    box-shadow: 0 6px 24px var(--overlay);
}

/* Report-a-problem: the category chips wrap. Everything else the form uses
   (.chip, .inp, .btn) is already declared above. */
.hk-report__types { display: flex; flex-wrap: wrap; gap: var(--sp-2); margin-bottom: var(--sp-3); }


:root {
    --hk-content-max: 1100px;
    --hk-topbar-bg: var(--surface);
    --hk-topbar-fg: var(--text);
    --hk-topbar-fg-muted: var(--muted);
    --hk-topbar-border: var(--border);
    /* Apps opt into the gradient variant by overriding this to a real gradient. */
    --hk-topbar-gradient: none;
    --hk-topbar-cta-fg: var(--primary);
}

/* ---------- App shell ---------- */
.hk-appshell {
    display: flex;
    flex-direction: column;
    min-height: 100vh;
    background: var(--bg);
    color: var(--text);
    font-family: var(--font);
}
.hk-appshell__content {
    flex-grow: 1;
    width: 100%;
    max-width: var(--hk-content-max);
    margin: 0 auto;
    padding: var(--sp-5) var(--sp-4);
    box-sizing: border-box;
}

/* ---------- Top bar ---------- */
.hk-topbar {
    position: sticky;
    top: 0;
    z-index: 20;
    background: var(--hk-topbar-bg);
    color: var(--hk-topbar-fg);
    border-bottom: 1px solid var(--hk-topbar-border);
    box-shadow: var(--shadow-1);
}
.hk-topbar__inner {
    display: flex;
    align-items: center;
    gap: var(--sp-5);
    max-width: var(--hk-content-max);
    margin: 0 auto;
    padding: var(--sp-3) var(--sp-4);
    box-sizing: border-box;
}
.hk-topbar__brand {
    font-size: 22px;
    font-weight: 800;
    letter-spacing: -0.01em;
    color: var(--hk-topbar-fg);
    /* A brand does not wrap. This matters once a slot holds a mark as well as a
       wordmark: an <a> slot is inline-flex and cannot break, but a <span> slot
       is an ordinary inline context and will put the mark on one line and the
       name on the next as soon as the nav crowds it. */
    white-space: nowrap;
}
.hk-topbar__brand a {
    color: inherit;
    text-decoration: none;
    display: inline-flex;
    align-items: center;
}
.hk-brandmark {
    display: inline-block;
    flex: none;
    background-color: currentColor;
    /* Spacing lives here, not on the parent's `gap`, because a brand slot is
       sometimes an <a> (inline-flex, so gap works) and sometimes a <span>
       (inline, so it does not). A logical margin needs no flex parent and
       spaces both identically, without changing any slot's layout mode.
       Assumes the mark leads the wordmark; a trailing mark wants the parent to
       be a flex row with a gap instead. */
    margin-inline-end: var(--sp-2);
    vertical-align: middle;
    -webkit-mask-repeat: no-repeat;
    mask-repeat: no-repeat;
    -webkit-mask-position: center;
    mask-position: center;
    -webkit-mask-size: contain;
    mask-size: contain;
}
.hk-topbar__nav {
    display: flex;
    align-items: center;
    gap: var(--sp-2);
}
.hk-topbar__spacer { flex-grow: 1; }
.hk-topbar__trailing {
    display: flex;
    align-items: center;
    gap: var(--sp-3);
}

/* Nav link — quiet by default, pill on hover/active. */
.hk-navlink {
    color: var(--hk-topbar-fg);
    text-decoration: none;
    font-size: var(--fs-body);
    font-weight: 500;
    padding: 6px 10px;
    border-radius: var(--r-sm);
    opacity: 0.86;
    transition: background var(--duration-short) var(--ease-standard),
                opacity var(--duration-short) var(--ease-standard);
}
.hk-navlink:hover {
    opacity: 1;
    background: rgba(0,0,0,0.05);
}
.hk-navlink--active {
    opacity: 1;
    background: rgba(0,0,0,0.06);
    font-weight: 600;
}

/* Trailing CTA pill. */
.hk-topbar__cta {
    padding: 7px 16px;
    background: var(--hk-topbar-fg);
    color: var(--hk-topbar-bg);
    border-radius: var(--r-pill);
    font-weight: 700;
    font-size: var(--fs-sm);
    text-decoration: none;
    letter-spacing: 0.02em;
    box-shadow: 0 1px 2px rgba(0,0,0,0.15);
}

/* ---------- Gradient variant ---------- */
/*
 * Opt-in: apps set `--hk-topbar-gradient` to their gradient (e.g.
 * "linear-gradient(135deg, #12263a, #204060 45%, #d9743a)") and add the
 * `hk-topbar-gradient` class. Inverts fg to white and gives nav links a
 * translucent hover.
 */
.hk-topbar-gradient {
    background: var(--hk-topbar-gradient);
    color: #fff;
    border-bottom-color: rgba(255,255,255,0.08);
    box-shadow: 0 2px 12px rgba(18,38,58,0.18);
}
.hk-topbar-gradient .hk-topbar__brand,
.hk-topbar-gradient .hk-navlink { color: #fff; }
.hk-topbar-gradient .hk-navlink:hover { background: rgba(255,255,255,0.14); }
.hk-topbar-gradient .hk-navlink--active { background: rgba(255,255,255,0.18); }
.hk-topbar-gradient .hk-topbar__cta {
    background: #fff;
    color: var(--hk-topbar-cta-fg);
}
/*
 * The gradient header is a fixed brand surface — it does not darken with the
 * rest of the page. Anything inside it therefore has to use on-brand ink, not
 * the page-surface tokens, which are tuned against --bg/--surface and vanish
 * here. Without these, Stoop's "Signed in" label rendered --muted directly on
 * the brass end of its gradient and was unreadable in *both* schemes, and its
 * sign-out button painted a dark --surface2 blob onto the header.
 */
.hk-topbar-gradient .muted,
.hk-topbar-gradient .hk-topbar__trailing .muted { color: rgba(255,255,255,0.82); }
.hk-topbar-gradient .btn-sm {
    background: rgba(255,255,255,0.16);
    color: #fff;
    border-color: rgba(255,255,255,0.38);
}
.hk-topbar-gradient .btn-sm:hover { background: rgba(255,255,255,0.26); border-color: rgba(255,255,255,0.6); }
.hk-topbar-gradient .btn-sm:focus-visible { outline: 2px solid #fff; outline-offset: 2px; }

/* ---------- Footer ---------- */
.hk-footer {
    padding: var(--sp-5) var(--sp-4);
    border-top: 1px solid var(--border);
    color: var(--muted);
    font-size: var(--fs-xs);
    text-align: center;
}
.hk-footer a { color: var(--muted); }

/* ---------- BottomNav (ships in v1.2.0) ---------- */
/*  Fixed to viewport bottom; flex row of items. Tokens use surface + border
    palette so it auto-themes with the app.  */
.hk-bottomnav {
    position: fixed;
    left: 0; right: 0; bottom: 0;
    display: flex;
    align-items: stretch;
    background: var(--surface);
    border-top: 1px solid var(--border);
    padding-bottom: env(safe-area-inset-bottom, 0);
    z-index: 40;
}
.hk-bottomnav__item {
    flex: 1;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    padding: var(--sp-2) var(--sp-1);
    cursor: pointer;
    color: var(--muted);
    font-size: var(--fs-xs);
    transition: color 120ms ease;
}
.hk-bottomnav__item:hover { color: var(--text); }
.hk-bottomnav__item.is-active { color: var(--primary); }
/* `--fs-2` (20px). This asked for `--fs-md`, which the type scale has never
   had — it runs `--fs-1/2/3` and then `--fs-body/sm/xs` — and with no fallback
   the declaration was dropped outright, so the icon inherited `--fs-xs` from
   `.hk-bottomnav__item` and rendered at exactly the size of its own 12px
   caption. */
.hk-bottomnav__icon { font-size: var(--fs-2); line-height: 1; margin-bottom: 2px; }
.hk-bottomnav__label { font-size: var(--fs-xs); }

