html, body {
    font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;
    margin: 0;
}

a, .btn-link { color: #006bb7; }

.btn-primary { color: #fff; background-color: #1b6ec2; border-color: #1861ac; }

.btn:focus, .btn:active:focus, .btn-link.nav-link:focus, .form-control:focus, .form-check-input:focus {
    box-shadow: 0 0 0 0.1rem white, 0 0 0 0.25rem #258cfb;
}

/* ── Shell ───────────────────────────────────────────────────────────────── */

.kc-shell { display: flex; min-height: 100vh; }

.kc-nav {
    width: 15rem;
    flex: 0 0 15rem;
    background: #17222e;
    color: #c9d4de;
    display: flex;
    flex-direction: column;
    padding: 1rem 0;
}

.kc-brand { padding: 0 1rem 1.25rem; display: flex; flex-direction: column; gap: .25rem; }
.kc-brand-row { display: flex; align-items: center; gap: .5rem; }
.kc-brand-name { font-size: 1.15rem; font-weight: 600; color: #fff; letter-spacing: .02em; }
.kc-env {
    font-size: .7rem; text-transform: uppercase; letter-spacing: .08em;
    color: #ffc86b; border: 1px solid #6b5a34; border-radius: 3px;
    padding: .05rem .35rem; align-self: flex-start;
}

.kc-link {
    display: flex; align-items: center; gap: .6rem;
    padding: .5rem 1rem; color: #c9d4de;
    text-decoration: none; border-left: 3px solid transparent; font-size: .93rem;
}
.kc-link:hover { background: #1e2b3a; color: #fff; }
.kc-link.active { background: #22334a; color: #fff; border-left-color: #4a9eff; }

/* Never shrinks, so the labels wrapping or being folded away cannot move the column of glyphs. */
.kc-icon { flex: 0 0 auto; opacity: .72; }
.kc-link:hover .kc-icon, .kc-link.active .kc-icon { opacity: 1; }
.kc-link-text { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* ── Folding the sidebar ─────────────────────────────────────────────────────
 *
 * Driven by data-nav on <html>, written by the head script in App.razor before first paint. A width
 * transition rather than a display swap so the main pane reflows once, smoothly, instead of the page
 * snapping — and the icons stay put throughout, which is what makes it read as folding rather than
 * as the navigation being replaced.
 */

.kc-nav-toggle {
    margin-left: auto;
    flex: 0 0 auto;
    display: flex; align-items: center; justify-content: center;
    inline-size: 1.5rem; block-size: 1.5rem;
    padding: 0;
    border: 1px solid #2b3b4d;
    border-radius: 4px;
    background: transparent;
    cursor: pointer;
}

.kc-nav-toggle:hover { background: #22334a; border-color: #3d5570; }

.kc-nav-toggle:focus-visible { outline: 2px solid #4a9eff; outline-offset: 1px; }

/* Two bars: a wide one and a narrow one, so it reads as "less of this" rather than as a menu icon
   that would suggest opening something. */
.kc-nav-toggle-mark {
    position: relative;
    inline-size: .7rem; block-size: 2px;
    background: #93a5b6;
    border-radius: 2px;
}

.kc-nav-toggle-mark::after {
    content: ''; position: absolute;
    inset-inline-start: 0; inset-block-start: 4px;
    inline-size: .4rem; block-size: 2px;
    background: #93a5b6; border-radius: 2px;
}

.kc-nav { transition: width .16s ease, flex-basis .16s ease; }

html[data-nav="collapsed"] .kc-nav { width: 3.75rem; flex-basis: 3.75rem; }

/* Everything that is words rather than a glyph. Hidden rather than removed, so nothing reflows
   inside the sidebar as it narrows. */
html[data-nav="collapsed"] .kc-link-text,
html[data-nav="collapsed"] .kc-brand-name,
html[data-nav="collapsed"] .kc-env,
html[data-nav="collapsed"] .kc-tenant,
html[data-nav="collapsed"] .kc-whoami-role,
html[data-nav="collapsed"] .kc-nav-foot form { display: none; }

html[data-nav="collapsed"] .kc-brand { padding: 0 0 .75rem; }
html[data-nav="collapsed"] .kc-brand-row { justify-content: center; }
html[data-nav="collapsed"] .kc-nav-toggle { margin-left: 0; }
html[data-nav="collapsed"] .kc-nav-toggle-mark { transform: rotate(180deg); }

/* Centred on the glyph, and the active marker stays on the edge where it was. */
html[data-nav="collapsed"] .kc-link { justify-content: center; padding-inline: 0 .1875rem; gap: 0; }

html[data-nav="collapsed"] .kc-nav-foot { padding: .5rem; }
html[data-nav="collapsed"] .kc-whoami-name {
    display: block; text-align: center; font-size: .7rem;
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}

@media (prefers-reduced-motion: reduce) {
    .kc-nav { transition: none; }
}

/* Below this the sidebar is a horizontal strip and there is no width to reclaim, so folding it would
   only hide the labels for nothing. */
@media (max-width: 900px) {
    html[data-nav="collapsed"] .kc-nav { width: auto; flex-basis: auto; }
    html[data-nav="collapsed"] .kc-link-text { display: inline; }
    html[data-nav="collapsed"] .kc-nav-toggle { display: none; }
}

.kc-nav-foot { margin-top: auto; padding: 1rem; }

.kc-main { flex: 1 1 auto; padding: 1.5rem 2rem; background: #f6f7f9; min-width: 0; }

/* ── Palettes ─────────────────────────────────────────────────────────────────
 *
 * Five swatches, not three. The two that were missing — background and text — are precisely the pair
 * that decides whether the menu can be read, so leaving them out of the preview meant the chip did
 * not show the thing most worth seeing.
 */

/* Where the operator currently is. Nine chips and five boxes gave no answer to "which one am I on?",
   and the moment a colour is nudged the honest answer stops being any of the chips. */
.kc-palette-now {
    display: flex; align-items: center; gap: .35rem; flex-wrap: wrap;
    margin-bottom: .6rem; padding: .3rem .55rem;
    background: #f6f8fa; border: 1px solid #e8ecf0; border-radius: 6px;
    font-size: .8rem;
}

.kc-palette-heading {
    font-size: .74rem; font-weight: 600; text-transform: uppercase; letter-spacing: .04em;
    color: #55636f; margin: .9rem 0 .4rem;
}

.kc-palette-heading:first-of-type { margin-top: 0; }

.kc-palette-hint {
    margin: .5rem 0 0; font-size: .76rem; line-height: 1.5; color: #6b7885;
}

/* Set apart, because it is the one control here that writes something new rather than filling boxes. */
.kc-palette-create {
    margin-top: 1rem; padding: .65rem .75rem;
    background: #f9fbfd; border: 1px solid #e3e9ef; border-radius: 7px;
}

.kc-palette-create .kc-palette-heading { margin-top: 0; }
.kc-palette-create .kc-palette-hint { margin-bottom: .6rem; }

.kc-palette {
    display: flex; align-items: center; gap: .5rem;
    padding: .3rem .55rem .3rem .35rem;
    border: 1px solid #d8dee4; border-radius: 7px;
    background: #fff; cursor: pointer;
    font: inherit; font-size: .8rem; color: inherit;
}

.kc-palette:hover { border-color: #9fb0c0; background: #fbfcfd; }
.kc-palette:focus-visible { outline: 2px solid #4a9eff; outline-offset: 1px; }

.kc-palette-strip { display: inline-flex; border-radius: 4px; overflow: hidden; flex: 0 0 auto;
    box-shadow: 0 0 0 1px rgba(0, 0, 0, .12); }
.kc-palette-strip > span { inline-size: .85rem; block-size: 1.35rem; }
.kc-palette-name { white-space: nowrap; }

/* A saved palette carries a delete, so the two controls travel together. */
.kc-palette-saved { display: inline-flex; align-items: stretch; }
.kc-palette-saved .kc-palette { border-radius: 7px 0 0 7px; }

.kc-palette-drop {
    border: 1px solid #d8dee4; border-left: 0; border-radius: 0 7px 7px 0;
    background: #fff; color: #b02a37; cursor: pointer;
    padding: 0 .4rem; font-size: .8rem;
}

.kc-palette-drop:hover { background: #fdf5f5; border-color: #e9a8a8; }

/* ── Contrast readout ─────────────────────────────────────────────────────────
 *
 * ⚠ The check that did not exist. readableOn covers text on the brand colours, but text and
 * background are both typed in by hand and nothing compared them — cream on white saved cleanly and
 * produced a menu that was blank to every guest.
 */

.kc-contrast { margin-top: 1rem; padding-top: .75rem; border-top: 1px solid #eef1f4; }

.kc-contrast-row { display: flex; align-items: center; gap: .5rem; margin-bottom: .3rem; }

/* The pair rendered as itself. A number is an argument; two letters in the actual colours is the
   evidence, and an operator can disagree with the number but not with what they can see. */
.kc-contrast-chip {
    display: inline-flex; align-items: center; justify-content: center;
    inline-size: 2rem; block-size: 1.5rem; flex: 0 0 auto;
    border: 1px solid rgba(0, 0, 0, .15); border-radius: 4px;
    font-size: .78rem; font-weight: 600;
}

.kc-contrast-label { font-size: .8rem; flex: 1 1 auto; min-width: 0; }
.kc-contrast-ratio { font-family: ui-monospace, Menlo, Consolas, monospace; font-size: .76rem; color: #55636f; }

.kc-contrast-verdict { font-size: .72rem; border-radius: 10px; padding: .05rem .4rem; }
.kc-contrast-verdict--good { background: #d8f0e3; color: #1d6b48; }
.kc-contrast-verdict--warn { background: #fdf0d5; color: #8a6116; }
.kc-contrast-verdict--bad { background: #fdecec; color: #96222d; }

.kc-contrast-warn {
    margin: .5rem 0 0; padding: .5rem .6rem;
    border-left: 3px solid #d99b28; border-radius: 0 6px 6px 0;
    background: #fdf6e8; color: #6b4f14; font-size: .78rem; line-height: 1.5;
}

/* ── Image picker ─────────────────────────────────────────────────────────────
 *
 * Upload first, URL underneath. Both, because every image on the live menus today is a URL and
 * dropping the box would make all of them uneditable until somebody found the original file again.
 */

.kc-image-row { display: flex; align-items: center; gap: .5rem; margin-bottom: .35rem; }

.kc-image-preview {
    width: 4rem; height: 2.6rem; object-fit: cover;
    border: 1px solid #e3e7eb; border-radius: 5px; background: #f6f7f9; flex: 0 0 auto;
}

.kc-image-none {
    display: flex; align-items: center; justify-content: center;
    width: 4rem; height: 2.6rem; flex: 0 0 auto;
    border: 1px dashed #d8dee4; border-radius: 5px; background: #f6f7f9;
    font-size: .62rem; color: #8b97a1;
}

.kc-image-actions { display: flex; align-items: center; gap: .3rem; }

/* The input sits inside its label, so focus and the accessible name come free and there is no
   synthetic click to go wrong. Hidden without display:none, which would take it out of the tab
   order and make the control unreachable by keyboard. */
.kc-image-input {
    position: absolute; width: 1px; height: 1px;
    padding: 0; overflow: hidden; clip-path: inset(50%); white-space: nowrap;
}

label.btn:has(.kc-image-input:focus-visible) { outline: 2px solid #4a9eff; outline-offset: 1px; }

.kc-image-error { font-size: .78rem; color: #b02a37; margin-top: .15rem; }
.kc-image-note { font-size: .75rem; color: #6b7885; margin-top: .15rem; }

/* ── Tables ──────────────────────────────────────────────────────────────── */

.kc-table { width: 100%; background: #fff; border-collapse: collapse; font-size: .88rem; }
.kc-table th {
    text-align: left; font-weight: 600; font-size: .74rem; text-transform: uppercase;
    letter-spacing: .04em; color: #5c6b7a; border-bottom: 2px solid #e3e7eb;
    padding: .5rem .6rem; white-space: nowrap;
}
.kc-table td { padding: .45rem .6rem; border-bottom: 1px solid #eef1f4; vertical-align: top; }
.kc-table tbody tr:hover { background: #f9fbfd; }

/* Wide content scrolls inside its own container so the page never scrolls sideways. */
.kc-scroll { overflow-x: auto; }

.kc-mono { font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; font-size: .82rem; }
.kc-num { text-align: right; font-variant-numeric: tabular-nums; }
.kc-dim { color: #78868f; }

/* ── Cards / panels ──────────────────────────────────────────────────────── */

.kc-card { background: #fff; border: 1px solid #e3e7eb; border-radius: 6px; padding: 1rem; }
.kc-card h2 { font-size: .95rem; font-weight: 600; margin: 0 0 .75rem; color: #2b3a4a; }

.kc-stat { display: flex; flex-direction: column; gap: .15rem; }
.kc-stat-value { font-size: 1.6rem; font-weight: 600; line-height: 1; }
.kc-stat-label { font-size: .75rem; text-transform: uppercase; letter-spacing: .04em; color: #6b7885; }

.kc-kv { display: grid; grid-template-columns: 11rem 1fr; gap: .3rem .75rem; font-size: .88rem; }
.kc-kv dt { color: #6b7885; font-weight: 500; }
.kc-kv dd { margin: 0; word-break: break-word; }

/* Raw POS/API payloads. Pre-wrapped and scrollable — a composed menu is 80 KB. */
.kc-payload {
    background: #101820; color: #d6e2ec; border-radius: 4px; padding: .6rem .75rem;
    font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
    font-size: .78rem; line-height: 1.45; max-height: 22rem; overflow: auto;
    white-space: pre-wrap; word-break: break-word; margin: 0;
}

.kc-timeline { list-style: none; margin: 0; padding: 0; }
.kc-timeline li { display: grid; grid-template-columns: 11rem 8rem 1fr; gap: .5rem;
    padding: .4rem 0; border-bottom: 1px solid #eef1f4; font-size: .87rem; }

.kc-empty { padding: 2rem; text-align: center; color: #78868f; background: #fff;
    border: 1px dashed #d8dee4; border-radius: 6px; }

/* ── Outlet configuration ───────────────────────────────────────────────────
   A name → POS reference pair. The label is fixed width so a column of them reads as a table without
   being one: the names are a closed vocabulary, so they never wrap and never need to. */
.kc-refrow { display: flex; align-items: center; gap: .5rem; margin-bottom: .35rem; }
.kc-refrow-label { flex: 0 0 7rem; margin: 0; font-size: .82rem; color: #55636d; }
.kc-refrow-input { flex: 1 1 auto; min-width: 0; }

/* What the outlet still needs. Amber rather than red as a whole, because the list mixes "a guest
   cannot order" with "the menu will look wrong" — and colouring both alike would teach an operator to
   read past the first one. Only the blocking entries take the marker. */
.kc-gaps { border: 1px solid #e6d4ae; border-inline-start: 3px solid #d99b28;
    background: #fdf6e8; border-radius: 6px; padding: .6rem .8rem; }
.kc-gaps-head { font-size: .82rem; font-weight: 600; color: #6b4f14; margin-bottom: .35rem; }
.kc-gaps-list { margin: 0; padding-inline-start: 1.1rem; font-size: .82rem; color: #6b4f14; }
.kc-gaps-list li { margin-bottom: .25rem; }
.kc-gaps-list li.kc-gap--blocking::marker { color: #96222d; font-weight: 700; }

@media (max-width: 900px) {
    .kc-shell { flex-direction: column; }
    .kc-nav { width: auto; flex: 0 0 auto; }
    .kc-main { padding: 1rem; }
    .kc-kv { grid-template-columns: 1fr; }
    .kc-timeline li { grid-template-columns: 1fr; }
}

/* ── text-bg-* shim ──────────────────────────────────────────────────────────
   The bundled Bootstrap is 5.1.0 and .text-bg-* arrived in 5.2, so every state
   badge was rendering Bootstrap's white badge text on no background at all —
   invisible, in the one column that says whether an order reached the POS. It
   failed silently because the class simply did not exist: nothing logs, nothing
   throws, the text is just white on white.

   Defined here rather than by upgrading Bootstrap, because a minor-version bump
   would restyle every page to fix one missing utility. Values are Bootstrap's own,
   so this becomes redundant rather than wrong if the bundle is ever upgraded. */
.text-bg-primary   { color: #fff !important; background-color: #0d6efd !important; }
.text-bg-secondary { color: #fff !important; background-color: #6c757d !important; }
.text-bg-success   { color: #fff !important; background-color: #198754 !important; }
.text-bg-danger    { color: #fff !important; background-color: #dc3545 !important; }
.text-bg-warning   { color: #000 !important; background-color: #ffc107 !important; }
.text-bg-info      { color: #000 !important; background-color: #0dcaf0 !important; }
.text-bg-light     { color: #000 !important; background-color: #f8f9fa !important; }
.text-bg-dark      { color: #fff !important; background-color: #212529 !important; }

/* ── Menu manager ────────────────────────────────────────────────────────────
   Three columns: what is left to place, where it goes, and what a guest ends up
   with. Side by side deliberately — the third column is the only feedback that an
   arrangement is right, and putting it behind a tab means nobody looks. */
.kc-mm { display: grid; grid-template-columns: 15rem minmax(0, 1fr) 19rem; gap: .75rem; align-items: start; }
.kc-mm-col { background: #fff; border: 1px solid #dfe4e9; border-radius: 6px; min-height: 8rem; }
.kc-mm-wide { background: #f6f8fa; }

.kc-mm-head { display: flex; align-items: center; gap: .5rem; padding: .5rem .65rem;
    border-bottom: 1px solid #e8ecf0; font-size: .78rem; font-weight: 600;
    text-transform: uppercase; letter-spacing: .04em; color: #55636f; }
.kc-mm-count { margin-left: auto; background: #eef1f4; border-radius: 10px; padding: 0 .45rem;
    font-size: .72rem; }
.kc-mm-sub { font-size: .78rem; font-weight: 600; color: #3e4c59; padding: .35rem .55rem .15rem; }

/* Drop affordance. The whole column highlights, not a thin line: a 1px target is
   the difference between an operator dragging once and dragging four times. */
.kc-mm-over { outline: 2px solid #0d6efd; outline-offset: -2px; background: #eaf2ff; }

.kc-slu { display: flex; align-items: center; gap: .45rem; margin: .3rem .4rem;
    padding: .35rem .5rem; background: #fff; border: 1px solid #d8dee4; border-radius: 4px;
    font-size: .84rem; cursor: grab; }
.kc-slu:active { cursor: grabbing; }
.kc-slu-placed { background: #fbfcfd; }
.kc-slu-num { display: inline-block; min-width: 1.5rem; text-align: center; background: #eef1f4;
    border-radius: 3px; font-family: ui-monospace, Menlo, Consolas, monospace; font-size: .72rem;
    color: #55636f; }

.kc-cat { margin: .4rem; background: #fff; border: 1px solid #d8dee4; border-radius: 5px; }
.kc-cat-head { display: flex; align-items: center; gap: .4rem; padding: .3rem .4rem;
    border-bottom: 1px solid #eef1f4; }
.kc-cat-name { flex: 1 1 auto; min-width: 4rem; border: 1px solid transparent; background: transparent;
    font-size: .9rem; font-weight: 600; padding: .15rem .3rem; border-radius: 3px; }
.kc-cat-name:hover { border-color: #d8dee4; }
.kc-cat-name:focus { border-color: #0d6efd; background: #fff; outline: none; }
.kc-cat-actions { display: flex; gap: .1rem; flex: 0 0 auto; }
.kc-cat-empty { padding: .5rem .6rem; font-size: .78rem; color: #8b97a1; font-style: italic; }

.kc-prev-cat { border-top: 1px solid #f0f3f5; }
.kc-prev-item { display: flex; align-items: center; gap: .4rem; padding: .22rem .55rem;
    font-size: .8rem; }
.kc-prev-item:hover { background: #f6f8fa; }
.kc-prev-hide { visibility: hidden; color: #b02a37; }
.kc-prev-item:hover .kc-prev-hide { visibility: visible; }
.kc-mm-featured { border-top: 1px solid #f0f3f5; background: #fffdf5; }

.kc-mm-warn { margin: .4rem; padding: .4rem .55rem; background: #fff8e6; border: 1px solid #ffe08a;
    border-radius: 4px; font-size: .78rem; color: #6b5416; }

/* Standing caveat rather than a dismissible alert: it is a property of the page, not news. */
.kc-notice { padding: .5rem .7rem; background: #eef4ff; border: 1px solid #c2d7fb;
    border-radius: 5px; font-size: .82rem; color: #29405f; }

@media (max-width: 1200px) {
    .kc-mm { grid-template-columns: 1fr; }
}

/* ── Accounts and password forms ───────────────────────────────────────────── */
.kc-form-card { background: #fff; border: 1px solid #dfe4e9; border-radius: 6px;
    padding: 1.1rem 1.2rem; max-width: 30rem; }
.kc-form-card .form-label { font-size: .85rem; margin-bottom: .2rem; }
.kc-form-card .form-text { font-size: .78rem; }

/* The reset link is a credential for the next hour, so it is framed as one rather
   than dropped into the page as ordinary text. */
.kc-reset-issued { padding: .75rem .9rem; background: #fff8e6; border: 1px solid #ffe08a;
    border-radius: 5px; font-size: .87rem; color: #5d4a12; }
.kc-reset-link { display: block; margin-top: .3rem; padding: .45rem .55rem; background: #fff;
    border: 1px solid #e6d8a8; border-radius: 4px; font-size: .8rem; word-break: break-all;
    color: #1f2933; }

.kc-whoami { display: block; text-decoration: none; color: inherit; }
.kc-whoami:hover .kc-whoami-name { text-decoration: underline; }

/* Which property is on screen. Sits directly under the brand because on a portal
   that can span tenants it changes what every page below it means. */
.kc-tenant { padding: .4rem 1rem .7rem; }
.kc-tenant-name { display: block; font-size: .82rem; color: #cdd8e3; }
.kc-tenant-select { width: 100%; padding: .25rem .4rem; font-size: .82rem;
    background: #1d2b3a; color: #e8eef4; border: 1px solid #33465b; border-radius: 4px; }
.kc-tenant-select:focus { outline: 2px solid #4d90d9; outline-offset: 1px; }

.kc-whoami-name { display: block; font-size: .84rem; color: #e8eef4; }
.kc-whoami-role { display: block; font-size: .74rem; color: #8fa3b6; text-transform: uppercase;
    letter-spacing: .04em; }

/* Image previews in the item-content editor. Loaded from the same address the guest app will use, so
   a URL that will not render here will not render there either — the border turns red on error, which
   is the one thing a validated string cannot tell you. */
.kc-thumb {
    inline-size: 2.6rem;
    block-size: 2.6rem;
    object-fit: cover;
    border-radius: 6px;
    border: 1px solid rgba(0, 0, 0, .15);
    background: rgba(0, 0, 0, .05);
    flex: 0 0 auto;
}

.kc-thumb--broken {
    border-color: #b02a37;
    border-style: dashed;
}

.kc-check {
    display: inline-flex;
    align-items: center;
    gap: .3rem;
    font-size: .8rem;
    cursor: pointer;
    user-select: none;
}
