/*
 * The Resort Manager Flex design system, as the console's own stylesheet.
 *
 * Same palette, type scale, radii and shadows as resortmanagerflex.com and as
 * ResortManager.Web, because an operator who administers both should not be
 * able to tell they have crossed between applications.
 *
 * Syncfusion's fluent2 theme is loaded first and this sits on top of it,
 * overriding its accent colours rather than restating its component rules.
 * Where a control is a Syncfusion one, it is left to the theme — a hand-drawn
 * dropdown next to a themed input was exactly the mismatch that made the last
 * console look unfinished.
 */

:root {
    --blue: #0A73B9;
    --blue-deep: #075E97;
    --ink: #0A2540;
    --ink-soft: #334A63;
    --accent: #EF8D20;
    --accent-deep: #D97C12;

    --bg: #F5F8FC;
    --bg-tint-2: #EDF3FA;
    --surface: #FFFFFF;
    --border: #E3EAF2;
    --muted: #5B6B7B;

    --text: var(--ink);
    --primary: var(--blue);
    --danger: #A2191F;
    --ok: #0E6027;

    /* The status palette, matching ResortManager.Web's own tint/ink pairs
       (app.css --rm-ok/--rm-ok-50 etc.) rather than a shade picked to taste —
       this is the one place a colour is doing real work, telling two states
       apart at a glance rather than decorating a page that was already grey
       and white. */
    --ok-tint: #E5F4ED;
    --warn: #B5630E;
    --warn-tint: #FBEFD9;
    --danger-tint: #FBE7E5;
    --info-ink: #075E97;
    --info-tint: #EDF3FA;
    --muted-tint: #E2E8F0;
    --muted-ink: #475569;

    --radius: 14px;
    --radius-sm: 10px;
    --shadow-sm: 0 1px 2px rgba(10, 37, 64, .06), 0 1px 3px rgba(10, 37, 64, .05);
    --shadow: 0 10px 30px -12px rgba(10, 37, 64, .18);

    --side-width: 248px;
    --header-height: 60px;
    /* The context band under the header: one line of .87rem at line-height 1.6, padded .5rem, and its border. */
    --context-height: 41px;

    --font: Inter, system-ui, -apple-system, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
}

/* Syncfusion's own tokens, pointed at ours, so its buttons, grids and inputs
   come out in Flex blue rather than bootstrap's. */
:root {
    --color-sf-primary: 10, 115, 185;
    --color-sf-primary-text-color: 255, 255, 255;
    --color-sf-success: 14, 96, 39;
    --color-sf-danger: 162, 25, 31;
    --color-sf-warning: 239, 141, 32;
    --color-sf-border: 227, 234, 242;
    --color-sf-content-text-color: 10, 37, 64;
}

* { box-sizing: border-box; }

/* Where an in-page link lands.

   .console-header is sticky at the top of the document, so a browser scrolling
   a heading to y=0 puts it behind the header — which is what QA saw following a
   Contents link into a guide: the section title and its first row were under
   the bar. The document is the scroller (the sidebar's position: sticky depends
   on that), so the padding belongs here rather than on .console-main, and it
   applies to every anchor in the console rather than only the guides'. */
html { scroll-padding-top: calc(var(--header-height) + var(--context-height) + 1rem); }

body {
    margin: 0;
    font-family: var(--font);
    background: var(--bg);
    color: var(--text);
    font-size: 15px;
    line-height: 1.6;
    -webkit-font-smoothing: antialiased;
}

h1, h2, h3 { line-height: 1.15; letter-spacing: -.02em; margin: 0; }

/* ---- shell ---- */

.console-header {
    position: sticky;
    top: 0;
    z-index: 50;
    background: var(--ink);
    color: #fff;
    padding: 0 20px;
    height: var(--header-height);
    display: flex;
    align-items: center;
    justify-content: space-between;
    box-shadow: var(--shadow-sm);
}

.console-brand { color: #fff; text-decoration: none; font-weight: 600; letter-spacing: -.01em; }
.console-brand strong { font-weight: 800; }

.console-signout {
    background: none;
    border: 0;
    padding: 0;
    cursor: pointer;
    font: inherit;
    color: #B9C6D6;
    font-size: .9rem;
    font-weight: 500;
}

.console-signout:hover { color: #fff; }

/* The band that says which of the two consoles this is. Two colours, because
   a wording difference alone is the kind of thing a tired person reads past. */
.console-context {
    display: flex;
    align-items: center;
    gap: .75rem;
    /* Held under the header, so the header, the band and the menu always fill the screen exactly. */
    position: sticky;
    top: var(--header-height);
    z-index: 40;
    height: var(--context-height);
    box-sizing: border-box;
    padding: 0 20px;
    background: var(--bg);
    font-size: .87rem;
    border-bottom: 1px solid var(--border);
}

.console-context-badge {
    font-weight: 700;
    font-size: .74rem;
    text-transform: uppercase;
    letter-spacing: .05em;
    padding: .15rem .55rem;
    border-radius: 999px;
    white-space: nowrap;
}

.console-context.is-operator { background: #FBF1E4; color: #6B4408; }
.console-context.is-operator .console-context-badge { background: var(--accent); color: #fff; }

.console-context.is-organisation { background: var(--bg-tint-2); color: var(--ink-soft); }
.console-context.is-organisation .console-context-badge { background: var(--blue); color: #fff; }

/* A third colour, and the strongest, for an operator standing inside a
   customer's console. The other two say which console you are in; this one says
   you are in somebody else's, which is the state where a mistaken click costs
   the most and the state a person is likeliest to forget they are in — the
   whole console below it looks exactly like the customer's own, because it is.
   Red, wraps rather than truncates, and carries the way out. */
.console-context.is-standing-in {
    background: #FCEDEC;
    color: #7A1F17;
    border-bottom: 2px solid var(--danger);
    flex-wrap: wrap;
}

.console-context.is-standing-in .console-context-badge {
    background: var(--danger);
    color: #fff;
}

/* Pushed to the end of the band, and back into the flow once the band wraps on
   a narrow screen — a way out that has scrolled off the side of a phone is not
   a way out. */
.console-context-action { margin-left: auto; }

@media (max-width: 720px) {
    .console-context-action { margin-left: 0; }
}

.console-body { display: flex; align-items: flex-start; }

.console-side {
    width: var(--side-width);
    flex: 0 0 var(--side-width);
    padding: 18px 12px 40px;
    border-right: 1px solid var(--border);
    background: var(--surface);
    /* The CRM's menu is longer than a laptop screen: it scrolls on its own beside the page, so a short page is one
       screen tall rather than the menu's height. */
    height: calc(100vh - var(--header-height) - var(--context-height));
    overflow-y: auto;
    overscroll-behavior: contain;
    position: sticky;
    top: calc(var(--header-height) + var(--context-height));
    align-self: flex-start;
}

.console-main { flex: 1 1 auto; padding: 24px 28px 60px; min-width: 0; }

/* ---- the moment before the page is live (D88) ---- */

/*
   Every console control is rendered disabled until the circuit has attached,
   so that neither a click nor a typed value can be swallowed in that window.
   These rules make that read as deliberate rather than as a page that has gone
   wrong.

   The cursor is the honest half: a control the browser has already greyed
   still invites the pointer, and "not yet" is what a person needs told before
   they press rather than after. Syncfusion's own :disabled styling does the
   dimming, so nothing here changes how a live page looks — these selectors
   match only while something is genuinely disabled, which includes a page's
   own busy states and should look the same there.
*/
.console button[disabled],
.console .e-btn[disabled],
.console input[disabled],
.console select[disabled] { cursor: not-allowed; }

.console input[type="checkbox"][disabled],
.console select[disabled] { opacity: .55; }

/*
   And the words, for a wait long enough to need them.

   Invisible for the first second and a quarter, because almost every load
   attaches its circuit inside that and a sentence shown and withdrawn in a
   blink is a flash on every single page. Past it, a form of greyed-out
   buttons has stopped reading as "in a moment" and needs saying out loud.

   The animation only carries the delay — there is no motion in it, so
   prefers-reduced-motion has nothing to honour and the sentence still arrives
   for a reader who has asked for stillness.
*/
.console-waking { display: none; }

.console[data-interactive="no"] .console-waking {
    display: block;
    margin: 0 0 1rem;
    padding: .55rem .85rem;
    border: 1px solid var(--border);
    border-radius: 6px;
    background: var(--bg-tint-2);
    color: var(--ink-soft);
    font-size: .9rem;
    opacity: 0;
    animation: rm-waking 1ms linear 1.25s forwards;
}

@keyframes rm-waking { to { opacity: 1; } }

/* ---- side menu ---- */

.console-nav-group { margin-bottom: 1.1rem; }

.console-nav-heading {
    font-size: .68rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: .08em;
    color: var(--muted);
    padding: 0 .65rem .3rem;
}

.console-nav-link {
    display: flex;
    align-items: center;
    gap: .6rem;
    padding: .4rem .65rem;
    border-radius: var(--radius-sm);
    color: var(--ink-soft);
    text-decoration: none;
    font-size: .91rem;
    font-weight: 500;
}

.console-nav-link:hover { background: var(--bg-tint-2); color: var(--ink); }

.console-nav-link.active {
    background: var(--blue);
    color: #fff;
    font-weight: 600;
}

.console-nav-icon { width: 1.1rem; text-align: center; opacity: .85; font-size: .95rem; }

/* ---- a group's heading folds its links (console.js writes which, as a sheet in <head>) ---- */

button.console-nav-heading {
    display: flex;
    align-items: center;
    justify-content: space-between;
    width: 100%;
    border: 0;
    background: none;
    font-family: inherit;
    text-align: left;
    cursor: pointer;
    border-radius: 6px;
}

button.console-nav-heading:hover { color: var(--ink); }
button.console-nav-heading:focus-visible { outline: 2px solid var(--blue); outline-offset: 1px; }
.console-nav-chevron { display: inline-block; width: .8rem; text-align: center; transition: transform .12s ease; }
.console-nav-chevron::before { content: "\25BE"; font-size: .7rem; }

/* ---- content ---- */

/* user-select: none because Routes.razor focuses this heading on every
   navigation (screen reader announcement), and a programmatic focus lands on
   text a mouse never touched — nothing for a sighted reader to select, and one
   fewer state (selected vs not) for a screenshot to catch mid-transition. */
.page-title { font-size: 1.4rem; font-weight: 800; margin-bottom: .2rem; user-select: none; }

/* Routes.razor focuses the page's <h1> on every navigation, for a screen
   reader announcing where it landed. The heading has no native focus ring of
   its own, so the browser drew its default — a heavy black box, since an h1
   is not normally focusable at all. Removed rather than restyled: the heading
   is not interactive and nothing is lost by a sighted reader not seeing where
   the invisible focus went. */
.page-title:focus { outline: none; }
/* The full width of the column it sits in, and it wraps. It was held to 62ch
   — a measure that reads well in a book and reads as a narrow strip beside a
   wide card, with the description of the page broken into four short lines
   while two thirds of the screen stayed empty. Nothing below it is measured
   in ch either. */
.page-lede { color: var(--muted); margin: 0 0 1.4rem; }

.card {
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    box-shadow: var(--shadow-sm);
    padding: 22px;
    margin-bottom: 20px;
}

.card h2 { margin: 0 0 .25rem; font-size: 1.05rem; font-weight: 800; }

/* ---- plain form controls, for the pages that cannot use Syncfusion ----

   The authentication journey renders without a circuit, deliberately: it writes
   cookies, which wants a response rather than a connection (ADR-0003). A
   Syncfusion control is JavaScript behind a Blazor facade and is inert without
   one, so those pages use ordinary inputs and buttons — and this is what makes
   them look like the rest of the console rather than like a browser default.

   Scoped to a card, and never to a Syncfusion element: .e-input-group carries
   its own border, and matching bare `input` here would put a second one inside
   it on every other page. */
.card label {
    display: block;
    margin: 0 0 .3rem;
    font-size: .82rem;
    font-weight: 600;
    color: var(--ink);
}

/* Includes an input with no type at all: Blazor's InputText emits none unless
   asked, so matching on type alone left half the fields at whatever width the
   browser felt like. */
.card input:not([type]),
.card input[type="text"],
.card input[type="email"],
.card input[type="password"],
.card input[type="tel"],
.card input[type="number"],
.card input[type="search"] {
    width: 100%;
    padding: 7px 10px;
    font: inherit;
    font-size: .95rem;
    color: var(--ink);
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
}

.card input:not([type]):focus,
.card input[type="text"]:focus,
.card input[type="email"]:focus,
.card input[type="password"]:focus,
.card input[type="tel"]:focus,
.card input[type="number"]:focus,
.card input[type="search"]:focus {
    outline: none;
    border-color: var(--blue);
    box-shadow: 0 0 0 2px color-mix(in srgb, var(--blue) 22%, transparent);
}

/* The two controls the block above forgot. A native select and textarea
   inside a card rendered browser-default — QA's screenshot of a bare Type
   dropdown and Choices box sitting between two themed fields — because only
   input was ever matched. Excluded from Syncfusion's by class, same as the
   inputs: its controls carry their own skin and e-* classes.

   This is the fix for the whole console at once, which is the point of doing
   it here: the next page that uses a native control inherits it instead of
   re-reporting this. */
.card select:not([class*="e-"]),
.card textarea:not([class*="e-"]) {
    width: 100%;
    padding: 7px 10px;
    font: inherit;
    font-size: .95rem;
    color: var(--ink);
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
}

.card select:not([class*="e-"]):focus,
.card textarea:not([class*="e-"]):focus {
    outline: none;
    border-color: var(--blue);
    box-shadow: 0 0 0 2px color-mix(in srgb, var(--blue) 22%, transparent);
}

.card textarea:not([class*="e-"]) { resize: vertical; }

/* A markup editor: reads as code, sized to edit code in, and grows rather
   than scrolling three words per line in a box the width of a playing card. */
.card textarea.rm-code {
    font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
    font-size: .85rem;
    line-height: 1.5;
    min-height: 420px;
    white-space: pre;
    tab-size: 2;
}

/* The submit on those same pages. Not `.card button`, which would repaint every
   Remove and Revoke in the console: only a button that carries no class of its
   own has asked for a default. */
.card button[type="submit"]:not([class]) {
    padding: 8px 14px;
    font: inherit;
    font-weight: 600;
    color: #fff;
    background: var(--blue);
    border: 1px solid var(--blue);
    border-radius: var(--radius-sm);
    cursor: pointer;
}

.card button[type="submit"]:not([class]):hover { filter: brightness(1.06); }

/* A checkbox keeps its label beside it rather than above. */
.card .check label { display: inline; margin: 0; font-weight: 500; }

/* ---- the public pages: signup and checkout ----

   Met by somebody who has no account yet. They sit on the plain layout, so
   there is no sidebar to sit beside and the column centres itself. */
.rm-public { max-width: 640px; margin: 0 auto; padding: 28px 0 48px; }

/* A form is a column and reads best narrow; a shop is a table and does not.
   The basket inherited the form's width and spent it on wrapping — a price
   broke across two lines, and the longest add-on name broke across two more. */
.rm-public:has(.rm-basket) { max-width: 900px; }

/* Only what it needs, so the item column keeps the rest. */
.rm-basket th:not(:first-child),
.rm-basket td:not(:first-child) { width: 1%; white-space: nowrap; }

/* The same heading the console sets, rather than a second scale of its own.
   These pages are met before an account exists and were drawn separately, which
   is how they ended up a different size and weight from every page the same
   person sees ten minutes later. */
.rm-public h1 { font-size: 1.4rem; font-weight: 800; margin: 0 0 .2rem; }
.rm-public .lede { color: var(--muted); margin: 0 0 1.4rem; max-width: 62ch; }
.rm-public .fine { font-size: .8rem; color: var(--muted); margin-top: 1.25rem; }

/* A card heading, as every console card has: the console never opens a card
   with a bare field, and a signup form that did read as a different product. */
.rm-public .card h2 { margin: 0 0 .25rem; }
.rm-public .card .card-lede {
    color: var(--muted);
    font-size: .85rem;
    margin: 0 0 1.25rem;
}


/* Two fields on a line where both are short, one under the other on a phone. */
.rm-public-row { display: grid; grid-template-columns: 1fr 1fr; gap: 0 18px; }
@media (max-width: 560px) { .rm-public-row { grid-template-columns: 1fr; } }

.rm-plans { display: grid; gap: .5rem; margin-bottom: .5rem; }

/* A choice that looks chosen. The row carried a border and nothing else, so a
   selected plan and an unselected one were the same picture and the only
   difference on screen was a radio dot. */
.card .rm-plan {
    display: flex;
    align-items: flex-start;
    gap: .7rem;
    padding: .85rem 1rem;
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
    background: var(--surface);
    cursor: pointer;
    font-weight: 500;
    transition: border-color .12s ease, background .12s ease;
}

.card .rm-plan:hover { border-color: var(--blue); }

.card .rm-plan:has(input:checked) {
    border-color: var(--blue);
    background: color-mix(in srgb, var(--blue) 6%, var(--surface));
    box-shadow: 0 0 0 1px var(--blue) inset;
}

.card .rm-plan input { accent-color: var(--blue); width: 16px; height: 16px; margin-top: .15rem; flex: none; }

/* The name on its own line, what it is for underneath — the shape the console
   uses everywhere it offers a choice worth explaining. */
.card .rm-plan .rm-plan-name { display: block; font-weight: 700; }
/* A tier with a quantity beside it: the name and price take the room, the
   box takes what it needs. */
.card .rm-plan-counted { justify-content: space-between; align-items: center; }
.card .rm-plan-counted input.rm-qty { width: 5rem; text-align: right; padding: 6px 8px; flex: none; }

.card .rm-plan .rm-plan-for { display: block; font-weight: 400; font-size: .82rem; color: var(--muted); margin-top: .15rem; }

/* The agreement tick, which is a sentence rather than a word: the box stays on
   the first line beside the text instead of centring itself against a
   paragraph, and the text keeps its ordinary weight so it reads as prose to be
   read rather than as another field label. */
.card .rm-accept {
    display: flex;
    align-items: flex-start;
    gap: .6rem;
    margin-top: 1.25rem;
    font-weight: 400;
    font-size: .9rem;
    line-height: 1.5;
    cursor: pointer;
}

/* The span carries the weight, because the label rule above it sets one and a
   sentence in the field-label weight reads as a heading for something. */
.card .rm-accept span { font-weight: 400; }

.card .rm-accept input {
    accent-color: var(--blue);
    width: 16px;
    height: 16px;
    margin-top: .15rem;
    flex: none;
}

/* The submit on these pages is the whole width, because it is the only thing
   being asked for. */
.rm-public .card button[type="submit"]:not([class]) { width: 100%; margin-top: 1.25rem; }

/* One thing for sale, and the button that buys it. */
.rm-offer {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 1rem;
    padding: .75rem 0;
    border-bottom: 1px solid var(--border);
}

.rm-offer:last-child { border-bottom: 0; }
.rm-offer .note { display: block; color: var(--muted); font-size: .85rem; }

/* ---- the basket ----

   Rows are chosen by quantity rather than bought one at a time. A Buy link per
   row meant a group taking three licences and an add-on left with four
   subscriptions and four card charges a month. */
/* How to pay, chosen once above the basket rather than doubled into it. */
.rm-period { display: flex; gap: .25rem; margin-bottom: 1rem; }

.rm-period a {
    padding: .45rem .9rem;
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
    font-size: .88rem;
    font-weight: 600;
    text-decoration: none;
    color: var(--ink);
    background: var(--surface);
}

.rm-period a:hover { border-color: var(--blue); }

.rm-period a.rm-period-on {
    background: var(--blue);
    border-color: var(--blue);
    color: #fff;
}

.rm-basket { margin-bottom: 1rem; }
.rm-basket .note { display: block; color: var(--muted); font-size: .85rem; }

/* Wide enough for two digits and no wider: a quantity box the width of a name
   field reads as somewhere to type a sentence. */
.card .rm-basket input.rm-qty {
    width: 5rem;
    text-align: right;
    padding: 6px 8px;
}

/* The total and the button on one line, the total first: what it costs is read
   before the thing that agrees to it. */
.rm-basket-bar {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 1rem;
    flex-wrap: wrap;
    padding-top: .5rem;
    border-top: 1px solid var(--border);
}

.rm-basket-total { margin: 0; font-weight: 700; }

/* The router focuses the heading on every navigation so a screen reader starts
   at the top of the new page. That focus is for announcing, not for pointing:
   it is not a control anybody tabbed to, and a ring drawn round the title on
   arrival reads as a text box. Only the programmatic one is hidden — a real
   tab stop keeps its ring. */
h1[tabindex="-1"]:focus,
h2[tabindex="-1"]:focus { outline: none; }
.card .hint { color: var(--muted); font-size: .87rem; margin: 0 0 1rem; max-width: 68ch; }

.notice, .error {
    border-radius: var(--radius-sm);
    padding: .7rem .9rem;
    margin-bottom: 1rem;
    font-size: .9rem;
}

.notice { background: #E7F3EC; color: var(--ok); border: 1px solid #C6E3D2; }
.error { background: #FBEAEA; color: var(--danger); border: 1px solid #F0CBCC; }

.empty { color: var(--muted); font-size: .9rem; padding: .6rem 0; }

/* A table that is not a list.

   What is left on this class after the lists became grids: a form laid out in
   rows (which field the portal asks for, and whether it is required), a
   translation side by side with its reference, a basket at checkout, a
   two-column count on the dashboard. None of them wants sorting, filtering or
   a pager — there is nothing to look up in four rows somebody is editing —
   but all of them sit next to a grid on the same screen, so they carry the
   grid's row metrics: the same 44-pixel tap target, the same padding, the
   same uppercase heading. Standard means it looks like one console, not that
   every table pretends to be a list. */
.console-table { width: 100%; border-collapse: collapse; }

.console-table th,
.console-table td {
    text-align: left;
    padding: .7rem .75rem;
    border-bottom: 1px solid var(--border);
    line-height: 1.45;
}

.console-table tbody td { min-height: 44px; }

/* A table whose columns are declared rather than measured, for the ones with a
   paragraph in a cell beside a column of numbers. Auto layout hands the
   paragraph the table and leaves the numbers a character wide; fixed layout
   gives every column the width its col says, and the paragraph wraps inside
   the one left over. */
.console-table--fixed { table-layout: fixed; }
.console-table--fixed td { overflow-wrap: anywhere; }

/* A note about the value beside it, rather than under it.

   The compliance packs put two sentences of law under a country code in a
   column seven characters wide, so a row that carried both was four lines of
   two-word fragments and the figures beside it sat against white space.
   Declaring the column wider only moved where the fragments broke. The pill
   holds the short form on one line and the sentence itself on hover, which is
   the same bargain the status pills make. */
.rm-note-pill {
    display: inline-block;
    margin-top: .25rem;
    padding: 1px 8px;
    border-radius: 999px;
    font-size: 11px;
    line-height: 1.5;
    font-weight: 600;
    letter-spacing: .02em;
    white-space: nowrap;
    background: var(--muted-tint);
    color: var(--muted-ink);
    cursor: help;
}

.console-table th {
    font-size: .72rem;
    text-transform: uppercase;
    letter-spacing: .06em;
    color: var(--muted);
    font-weight: 700;
}

.console-table tbody tr:hover { background: var(--bg-tint-2); }
.console-table .numeric { text-align: right; }
.console-table code { font-size: .85em; }

.muted { color: var(--muted); font-size: .87rem; }

/* Two facts on one line in a grid cell, the second one giving way first.
   A stacked name and email doubled the height of every row on the page that
   uses it, including the rows that had no email to stack. min-width:0 on the
   flex child is what lets the ellipsis happen at all: without it the text
   sets the box's floor and the cell widens instead of clipping. */
.rm-oneline { display: flex; gap: .5rem; align-items: baseline; min-width: 0; }
.rm-oneline > * { min-width: 0; }
.rm-oneline > .muted { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* ---- status pills ----

   The same convention as ResortManager.Web's own rm-status-pill: a status
   word gets a class of its own lower-cased name, and the bucket below picks
   its colour. Green for a state that is working as intended, blue for one
   in progress or waiting, amber for one that wants attention without being
   wrong, red for one that has stopped, grey for one that was never live.
   Everything else — a name, a code, a date — stays plain text; a pill on
   every cell is a pill on none of them. */
.rm-status-pill {
    display: inline-block;
    padding: 1px 8px;
    border-radius: 999px;
    font-size: 11px;
    line-height: 1.5;
    font-weight: 600;
    letter-spacing: .02em;
    margin: 0;
    background: var(--muted-tint);
    color: var(--muted-ink);
    vertical-align: middle;
}

.rm-status-pill.rm-status-active,
.rm-status-pill.rm-status-yes,
.rm-status-pill.rm-status-verified,
.rm-status-pill.rm-status-inhouse,
.rm-status-pill.rm-status-granted,
.rm-status-pill.rm-status-sent,
.rm-status-pill.rm-status-enrolled,
.rm-status-pill.rm-status-onsale,
.rm-status-pill.rm-status-signingin,
.rm-status-pill.rm-status-connected,
.rm-status-pill.rm-status-delivered,
.rm-status-pill.rm-status-opened,
.rm-status-pill.rm-status-clicked,
.rm-status-pill.rm-status-ok { background: var(--ok-tint); color: var(--ok); }

.rm-status-pill.rm-status-pending,
.rm-status-pill.rm-status-scheduled,
.rm-status-pill.rm-status-sending,
.rm-status-pill.rm-status-paddle,
.rm-status-pill.rm-status-unrestricted { background: var(--info-tint); color: var(--info-ink); }

.rm-status-pill.rm-status-warn,
.rm-status-pill.rm-status-expiring,
.rm-status-pill.rm-status-notyetenrolled,
.rm-status-pill.rm-status-draft { background: var(--warn-tint); color: var(--warn); }

.rm-status-pill.rm-status-ended,
.rm-status-pill.rm-status-departed,
.rm-status-pill.rm-status-revoked,
.rm-status-pill.rm-status-disabled,
.rm-status-pill.rm-status-inactive,
.rm-status-pill.rm-status-expired,
.rm-status-pill.rm-status-no,
.rm-status-pill.rm-status-notsigningin,
.rm-status-pill.rm-status-cancelled,
.rm-status-pill.rm-status-removed,
.rm-status-pill.rm-status-noplan,
.rm-status-pill.rm-status-failing,
.rm-status-pill.rm-status-bounced,
.rm-status-pill.rm-status-spamreport,
.rm-status-pill.rm-status-failed,
.rm-status-pill.rm-status-danger { background: var(--danger-tint); color: var(--danger); }

.rm-status-pill.rm-status-notforsale { background: var(--muted-tint); color: var(--muted-ink); }

/* A picker inside a table cell. The column sizes to its content and a closed
   dropdown has almost none, so without a floor it collapses to an ellipsis —
   "Not r…" — and the cell stops saying which model the router is. The table
   already scrolls sideways on a phone, so a floor here costs nothing there. */
.console-table .e-input-group.e-ddl { min-width: 11rem; }

/* A group heading inside a table, spanning every column. What used to be an
   h2 above a table of its own — which is how five sections ended up with five
   different column positions. Styled as the section heading it replaces. */
.console-table tr.console-table-group th {
    padding: 22px 12px 6px;
    border-bottom: 1px solid var(--border);
    font-size: 13px;
    font-weight: 700;
    letter-spacing: .08em;
    text-transform: uppercase;
    color: var(--muted);
    text-align: left;
    background: transparent;
}

.console-table tr.console-table-group:first-child th { padding-top: 4px; }

/* Headline numbers. Flex rather than a grid, so four figures on a desktop
   become two and two on a tablet and one column on a phone without a rule
   per breakpoint. */
/* The first-run checklist on the dashboard: one line per step, a tick in
   front of the ones the console has evidence for. */
.rm-checklist-steps { list-style: none; margin: .5rem 0 0; padding: 0; }
.rm-checklist-steps li {
    display: flex; gap: .75rem; align-items: flex-start;
    padding: .6rem 0; border-top: 1px solid var(--border);
}
.rm-checklist-steps li div { display: flex; flex-direction: column; gap: .15rem; }
.rm-checklist-mark {
    flex: 0 0 1.5rem; height: 1.5rem; border-radius: 50%;
    border: 2px solid var(--border); font-size: .9rem; font-weight: 800;
    display: inline-flex; align-items: center; justify-content: center;
}
.rm-checklist-steps li.done .rm-checklist-mark { background: var(--primary); border-color: var(--primary); color: #fff; }
.rm-checklist-steps li.done strong { color: var(--muted); font-weight: 600; }

/* The getting-started page: one card per step. The open one is plain, a
   done one is quiet, and a later one is dimmed until its turn. */
.rm-step h2 { display: flex; align-items: center; gap: .6rem; }
.rm-step.done .rm-checklist-mark { background: var(--primary); border-color: var(--primary); color: #fff; }
.rm-step.later { opacity: .55; }
.rm-checks { display: flex; flex-direction: column; gap: .4rem; }
.rm-checks label { display: flex; gap: .5rem; align-items: baseline; font-weight: 400; }
.rm-checks label strong { font-weight: 700; }

.figures { display: flex; flex-wrap: wrap; gap: 1rem; }

.figure {
    flex: 1 1 10rem;
    min-width: 0;
    background: var(--bg-tint-2);
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
    padding: 1rem;
}

.figure .value { display: block; font-size: 1.8rem; font-weight: 800; line-height: 1.1; overflow-wrap: anywhere; }
.figure .label { display: block; font-size: .85rem; font-weight: 600; margin-top: .25rem; }
.figure .note { display: block; font-size: .75rem; color: var(--muted); margin-top: .35rem; }

/* Bars drawn with divs. This console has no build step and no CDN is
   reachable from some of the places it is opened from, so a charting library
   would be a dependency that fails exactly where it is needed. */
.bars { display: flex; align-items: flex-end; gap: 3px; height: 140px; margin-bottom: .75rem; }
.bar { flex: 1; height: 100%; display: flex; align-items: flex-end; }
.bar .fill { width: 100%; background: var(--blue); border-radius: 3px 3px 0 0; min-height: 2px; }

/* A checkbox and its label on one line, top-aligned so a two-line label does
   not drag the box down with it. */
.check { display: flex; gap: 10px; align-items: flex-start; margin: 2px 0 12px; }
.check input { margin-top: 4px; flex: 0 0 auto; width: 16px; height: 16px; accent-color: var(--blue); }
.check label { margin: 0; font-weight: 500; }

/* The bar above a list: what narrows it before the grid gets it.

   A row rather than a stack, because these are one question asked in two or
   three parts — a search, a tick, a tick — and stacked they read as three
   separate settings and push the list itself off the screen. The search box is
   given a measure rather than the card's full width: an address is forty
   characters and a box twice that says nothing more. */
.console-filters {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px 16px;
    margin-bottom: 1rem;
}

.console-filters .check { margin: 0; }

.rm-search { flex: 0 1 24rem; min-width: 14rem; }
.rm-search input { width: 100%; }

/* A card announcing something that went right, next to one that did not. */
.card-good { border-color: var(--ok); }

.actions { white-space: nowrap; }

/* A value that is a problem. Named rather than styled inline, so every page
   says "this went wrong" the same way. */
.bad { color: var(--danger); }
.actions form { display: inline; }

/* A value shown exactly once. Monospaced and selectable in one gesture,
   because the next thing that happens to it is a copy into a password
   manager. */
.secret {
    display: inline-block;
    max-width: 100%;
    overflow-wrap: anywhere;
    user-select: all;
    font-size: 1.05rem;
    letter-spacing: .04em;
    padding: .5rem .7rem;
    background: var(--bg-tint-2);
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
}

/* A command somebody will copy. Wrapped rather than scrolled: a curl line that
   runs off the edge is one that gets copied in half. */
.console-code {
    white-space: pre-wrap;
    word-break: break-all;
    padding: .75rem;
    background: var(--bg-tint-2);
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
    font-size: .82rem;
    margin: 0;
}

/* Fields wrap rather than squeeze: this console is often read on a phone at a
   front desk, and a three-column row at 380px is three unusable columns. */
.form-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(230px, 1fr));
    gap: .9rem 1.1rem;
}

.form-grid label { display: block; }

.form-grid label > span {
    display: block;
    font-size: .78rem;
    font-weight: 700;
    letter-spacing: .03em;
    text-transform: uppercase;
    color: var(--muted);
    margin-bottom: .3rem;
}

@media (max-width: 900px) {
    .console-body { display: block; }

    /* A phone's band wraps onto more lines, so it scrolls away with the page. */
    .console-context { position: static; height: auto; padding: .5rem 20px; flex-wrap: wrap; }

    .console-side {
        width: auto;
        position: static;
        min-height: 0;
        height: auto;
        overflow-y: visible;
        border-right: 0;
        border-bottom: 1px solid var(--border);
    }

    .console-main { padding: 18px 16px 48px; }
}

/* ============================================================
   The form system, ported from ResortManager.Web (2026-08-22).

   Same class names, same shapes, same rules as app.css and
   app.forms.css there. Not similar-looking — the same, because
   the complaint that produced this was that the two applications
   do not feel like one product, and a second vocabulary that
   merely resembles the first is how that happens again.

   Everything below sits on this file's own tokens, which are
   already the Flex palette Web draws from.
   ============================================================ */

/* ---- a field ---- */

.rm-field { margin-bottom: 14px; min-width: 0; }

.rm-field-label {
    display: block;
    font-size: 12px;
    color: var(--muted);
    font-weight: 500;
    margin-bottom: 6px;
    letter-spacing: .02em;
    min-height: 18px;   /* holds the row open for a label-less cell */
}

.rm-field-required { color: var(--danger); margin-left: .2rem; font-weight: 600; }

/* The hint, as an icon rather than a paragraph. This is the single biggest
   reason a dense form fits on a screen: the same text inline under each
   control doubles the height of every card it appears in. The full wording
   lives in the title and the aria-label, so it is available without a
   pointer. */
.rm-field-hint-icon {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 13px;
    height: 13px;
    margin-left: 5px;
    border: 1px solid currentColor;
    border-radius: 50%;
    font-style: italic;
    font-weight: 700;
    font-size: 9px;
    line-height: 1;
    color: var(--muted);
    cursor: help;
    user-select: none;
    vertical-align: middle;
    flex: 0 0 auto;
    transition: color .12s ease;
}

.rm-field-hint-icon:hover,
.rm-field-hint-icon:focus-visible { color: var(--primary); outline: none; }
.rm-field-hint-icon--trailing { margin-left: 8px; vertical-align: baseline; }

/* Every Syncfusion control fills its cell. Left alone they take their own
   intrinsic width, which leaves a wide card full of narrow boxes. */
.rm-field-control { width: 100%; }

.rm-field-control > .e-control,
.rm-field-control > .e-input-group,
.rm-field-control > .e-textbox,
.rm-field-control > .e-numerictextbox,
.rm-field-control > .e-datepicker,
.rm-field-control > .e-datetimepicker,
.rm-field-control > .e-dropdownlist,
.rm-field-control > .e-multiselect,
.rm-field-control > input,
.rm-field-control > textarea,
.rm-field-control > select,
.rm-field-control > div { width: 100%; }

.rm-field-control .e-input-group { width: 100%; }

/* ---------------- Syncfusion Fluent2 brand overrides ----------------

   ResortManager.Web's own block (app.css, "Syncfusion Fluent2 brand
   overrides"), ported rather than reinvented: buttons, inputs, the grid,
   the dialog, tabs, the pager, tooltips and toasts, all pulled onto this
   console's tokens. Global rather than scoped to .rm-field-control — a
   Syncfusion control anywhere on this console is one of these controls,
   not only the ones a form happens to wrap. This is what "Display name"
   and "User name" on the VIP page turned out to need: fluent2.css supplies
   a border on .e-input-group in its own right, but on this console it
   rendered close enough to invisible against a white card that the field
   read as loose text with nothing around it — on every plain text or
   numeric field on every page, not only those two. */

.e-btn,
.e-css.e-btn {
    border-radius: var(--radius-sm) !important;
    font-family: var(--font) !important;
    font-weight: 500 !important;
    letter-spacing: 0;
    padding: 0 14px;
    height: 36px;
    line-height: 36px;
    transition: background .15s ease, border-color .15s ease, box-shadow .15s ease;
}

.e-btn.e-small, .e-css.e-btn.e-small { height: 30px; line-height: 30px; padding: 0 10px; font-size: 12.5px; }
.e-btn.e-icon-btn, .e-css.e-btn.e-icon-btn { padding: 0 8px; }

.e-btn.e-primary,
.e-css.e-btn.e-primary { background: var(--blue); border-color: var(--blue); color: #fff; }
.e-btn.e-primary:hover, .e-css.e-btn.e-primary:hover { background: var(--blue-deep); border-color: var(--blue-deep); }
.e-btn.e-primary:active, .e-btn.e-primary:focus { background: var(--blue-deep); border-color: var(--blue-deep); box-shadow: 0 0 0 2px rgba(10, 115, 185, .18); }
.e-btn.e-flat:not(.e-primary):hover { background: var(--bg-tint-2); }

/* A destructive action's own colour, and white on it.

   The theme draws e-danger as the danger colour's own text on a tint of
   itself, which came out at 2.6:1 — so Delete, Revoke, Remove, Purge and
   Withdraw, the labels a person most needs to read before pressing, were the
   hardest on the page. White on the console's danger red is 7.8:1, and it is
   already the pairing the confirmation these buttons open is drawn in, so the
   button and the answer it asks for now read as one act. */
.e-btn.e-danger,
.e-css.e-btn.e-danger { background: var(--danger); border-color: var(--danger); color: #fff; }

.e-btn.e-danger:hover,
.e-btn.e-danger:active,
.e-btn.e-danger:focus,
.e-css.e-btn.e-danger:hover { background: #87151A; border-color: #87151A; color: #fff; }

.e-btn.e-danger:focus-visible { box-shadow: 0 0 0 3px rgba(162, 25, 31, .3); }

/* ---- the grid ----

   Every list in the console is one of these, and the metrics are here rather
   than on each call so that "a row" means one thing on every page.

   The rows used to be 28 pixels. That is a desktop density: fine under a
   mouse, and a coin toss under a thumb. These pages are opened on a tablet at
   reception and on a phone in a corridor, so a row is a tap target first and
   a line of text second, and 44 pixels is the smallest one a finger hits
   reliably. Ten of those, a header and a pager come to roughly a screen,
   which is why RmGrid pages at ten: the reader sees a whole page and the
   control that moves to the next one without scrolling to discover there is
   one.

   No !important anywhere below. The rules the theme needs beating are matched
   on specificity instead, so a page that genuinely needs a different number
   can still say so. */
.e-grid { border: 1px solid var(--border); border-radius: var(--radius); overflow: hidden; }

/* Eight pixels each side rather than twelve. A heading is set in small
   capitals and shares its cell with the sort and filter icons, which between
   them take about forty-four pixels of the column before a letter is drawn —
   so four pixels of padding is four pixels of heading, on every column of
   every list, and it is the difference between "THIS MONTH" and "THIS MON…". */
.e-grid .e-headercell {
    background: var(--bg-tint-2);
    border-bottom: 1px solid var(--border);
    height: 44px;
    padding: 0 8px;
    vertical-align: middle;
}

/* Centred by the cell rather than by a line-height equal to the header's own
   height, which is what it used to be: "Last heard from" is three words, and a
   40-pixel line under a 40-pixel heading put two of them outside it. */
.e-grid .e-headercelldiv {
    font-size: 11px;
    font-weight: 700;
    letter-spacing: .06em;
    text-transform: uppercase;
    color: var(--muted);
    line-height: 1.35;
}

/* A heading wraps between its words and never inside one.

   Asking the grid to wrap its text (which a cell holding an address or a
   failure sentence needs) turns on the theme's own rule for headings too, and
   that one is overflow-wrap: break-word — so "Router" came out as "ROU / TER"
   and "Country" as "COUNTR / Y", which read as typos rather than as columns.
   Matched selector-for-selector with the theme's, because anything shorter
   loses to it. */
.e-grid.e-wrap .e-columnheader .e-headercelldiv,
.e-grid.e-wrap .e-columnheader .e-headercell.e-fltr-icon .e-headercelldiv {
    overflow-wrap: normal;
    word-wrap: normal;
    word-break: keep-all;
}

.e-grid .e-gridcontent .e-rowcell {
    font-size: 13px;
    padding: 10px 12px;
    border-bottom-color: var(--border);
    line-height: 1.45;
    box-sizing: border-box;
}

.e-grid .e-gridcontent .e-row { height: auto; }
.e-grid .e-gridcontent .e-row .e-rowcell { min-height: 44px; }
.e-grid .e-row:hover .e-rowcell { background: var(--bg-tint-2); }

/* The sort and filter icons in a heading are positioned by the theme, and are
   left to it. An earlier version of this file gave them the header's full
   height to make them easier to tap; they are absolutely positioned, so what
   that actually did was take them out of the header's own measurement — and
   the grid, sizing a column to its header, gave the first column about one
   character and wrapped a customer's name down the page. The tap target is the
   header cell, which is 44 pixels tall and is what a finger lands on. */

/* A cell holding buttons rather than a value. Never wrapped: a column's
   AutoFit measures this cell's natural width to size the column, and a
   flex container allowed to wrap measures as narrow as its widest single
   button rather than as wide as all of them, which is what actually used
   to put "Replace price" and "Withdraw" each on their own line. Kept to one
   line, the column AutoFit gives it is the width the buttons need; the
   grid's own horizontal scroll under 700px is the fallback for a screen
   too narrow for that. */
.e-grid .e-rowcell .actions {
    display: flex;
    flex-wrap: nowrap;
    gap: 6px;
    align-items: center;
}

.e-grid .e-rowcell .actions form { display: inline-flex; margin: 0; }

/* The pager. Its numbers are links somebody taps, so they are sized like
   links somebody taps — the theme's own are around 24 pixels square. */
.e-grid .e-gridpager { border-top: 1px solid var(--border); padding: 8px 10px; }

.e-grid .e-gridpager .e-numericitem,
.e-grid .e-gridpager .e-icons.e-icon-first,
.e-grid .e-gridpager .e-icons.e-icon-prev,
.e-grid .e-gridpager .e-icons.e-icon-next,
.e-grid .e-gridpager .e-icons.e-icon-last {
    min-width: 40px;
    height: 40px;
    line-height: 40px;
    font-size: 13px;
}

.e-grid .e-gridpager .e-currentitem { background: var(--blue); color: #fff; border-radius: var(--radius-sm); }

/* The toolbar carries one thing, the search box, and it reads as part of the
   grid's frame rather than as a component parked on top of it. */
.e-grid .e-toolbar { border-bottom: 1px solid var(--border); background: var(--bg-tint-2); }
.e-grid .e-toolbar .e-toolbar-items { background: transparent; }
.e-grid .e-toolbar .e-input-group.e-search { min-height: 40px; }

/* A picker or a text box inside a cell — a plan chosen per venue, a router's
   model. Given room, because a closed dropdown truncated to "Not r…" is a
   cell that has stopped saying anything. */
.e-grid .e-rowcell .e-input-group.e-ddl { min-width: 11rem; }

/* A grid that follows a paragraph rather than a heading, and needs the air
   the paragraph would otherwise be sitting on. */
.rm-grid--spaced { margin-top: 1rem; }

/* A grid below a desk's width.

   The side menu is above the page rather than beside it from 900px down, so
   the card is the width of the window, and a grid measured for a desk does
   not fit it: the columns are sized in pixels, a row of eight of them adds up
   to more than a tablet holds, and the grid ran up to 582 pixels past its
   card while the columns that declared nothing were squeezed to three.

   So below that width a console grid stops being a measured table: its own
   measurements go, the table is the card, and the fixed layout divides that
   card equally between the columns still in the row. It fits at any width by
   construction, and which columns are still in the row is the page's business
   — a column not worth a tablet carries ConsoleColumns.AtADesk and leaves.

   !important, which nothing else about the grid needs. The widths being
   beaten are written onto the table and its columns by the grid itself as it
   measures, and a style attribute is not something a selector can outrank. */
@media (max-width: 900px) {
    .e-grid .e-table { width: 100% !important; min-width: 0 !important; }
    .e-grid colgroup col { width: auto !important; }

    /* Except the two columns that are not columns of text: the expander on a
       grid whose rows open, and the indent in front of a grouped row. An
       equal share of a tablet's card is four-fifths of it spent on an icon. */
    .rm-grid--detail .e-grid colgroup col:first-child,
    .rm-grid--grouped .e-grid colgroup col:first-child { width: 44px !important; }

    /* A cell of buttons stacks rather than being cut off. At a desk it never
       wraps — the column is measured to hold its buttons on one line, and a
       second line nobody scrolled to was the defect that rule was written for
       — but an equal share of a tablet's card is narrower than any row of
       buttons, and a button on a second line is one a person can still press. */
    .e-grid .e-rowcell .actions { flex-wrap: wrap; }

    /* And a label of three words wraps inside its own button rather than
       running out of the column: "Send Password Reset" is 141 pixels on one
       line, which is most of an equal share of a tablet's card. */
    .e-grid .e-rowcell .actions .e-btn {
        white-space: normal;
        height: auto;
        min-height: 30px;
        line-height: 1.25;
        padding: 5px 10px;
    }

    /* And a picker in a cell takes the cell's width rather than the 11rem it
       is given at a desk, which is wider than an equal share of a tablet's
       card and would hang over the column beside it. */
    .e-grid .e-rowcell .e-input-group.e-ddl { min-width: 0; }
}

/* Narrow screens: the grid scrolls sideways inside its card rather than
   pushing the page off the phone. Syncfusion's own adaptive dialogs handle
   sorting and filtering at this width — RmGrid asks for them — so all that is
   left here is the frame. */
@media (max-width: 700px) {
    .rm-grid { overflow-x: auto; }
    .e-grid .e-gridcontent .e-rowcell { padding: 12px; }
}

/* Inputs — a solid bordered box, everywhere, rather than Syncfusion's default
   underline style, which reads as unfinished against a form built of bordered
   cards and bordered plain inputs. */
.e-input-group,
.e-float-input,
.e-input-group.e-control-wrapper {
    border: 1px solid var(--border) !important;
    border-radius: var(--radius-sm) !important;
    background: #fff !important;
    overflow: hidden;
    transition: border-color .15s ease, box-shadow .15s ease;
}

.e-input-group.e-disabled,
.e-input-group input.e-input[readonly],
.e-input-group input.e-input:read-only {
    background: var(--bg-tint-2) !important;
    color: var(--text) !important;
}
.e-input-group.e-disabled { border-color: var(--border) !important; opacity: 1 !important; }

.e-input-group:not(.e-disabled):not(.e-success):not(.e-warning):not(.e-error):hover {
    border-color: var(--blue) !important;
}
.e-input-group.e-input-focus,
.e-input-group:not(.e-disabled):not(.e-success):not(.e-warning):not(.e-error).e-input-focus {
    border-color: var(--blue) !important;
    box-shadow: 0 0 0 3px rgba(10, 115, 185, .12) !important;
}

/* The legacy underline pseudo-elements, killed rather than left to double up
   under the border above. */
.e-input-group:not(.e-disabled):not(.e-success):not(.e-warning):not(.e-error):before,
.e-input-group:not(.e-disabled):not(.e-success):not(.e-warning):not(.e-error):after,
.e-input-group:not(.e-disabled):not(.e-success):not(.e-warning):not(.e-error):hover:before,
.e-input-group:not(.e-disabled):not(.e-success):not(.e-warning):not(.e-error):hover:after { display: none !important; }

.e-input-group input.e-input,
.e-input-group .e-input,
.e-float-input input {
    font-family: var(--font) !important;
    height: 38px;
    padding: 0 12px !important;
    font-size: 14px;
    color: var(--text);
}

.e-input-group textarea.e-input,
.e-float-input textarea {
    height: auto;
    min-height: 76px;
    padding: 8px 12px !important;
    resize: vertical;
}

.e-input-group .e-input-group-icon { color: var(--muted); }

/* Dialog */
.e-dialog { border-radius: var(--radius); border: 1px solid var(--border); box-shadow: var(--shadow); }
.e-dialog .e-dlg-header-content { border-bottom: 1px solid var(--border); padding: 16px 20px; }
.e-dialog .e-dlg-header { font-family: var(--font); font-size: 18px; letter-spacing: -.015em; font-weight: 600; color: var(--ink); }
.e-dialog .e-dlg-content { padding: 20px; }
.e-dialog .e-footer-content { padding: 14px 20px; border-top: 1px solid var(--border); background: var(--bg-tint-2); }

/* The confirmation every destructive button asks through (RmConfirmDialog).
   Never wider than the screen it is on: a phone at reception is where a
   mistaken tap on Delete happens. The button that goes ahead is white on the
   console's own danger red, 7.9:1, so the label that matters most is the
   easiest to read; the buttons stack full width on a phone so neither is a
   small target beside the other. */
.e-dialog.rm-confirm { max-width: calc(100vw - 24px); }
.rm-confirm .e-dlg-content p { margin: 0 0 .75rem; color: var(--ink-soft); line-height: 1.5; }
.rm-confirm .e-dlg-content p:last-child { margin-bottom: 0; }
.rm-confirm .rm-confirm__buttons { display: flex; flex-wrap: wrap; justify-content: flex-end; gap: 8px; width: 100%; }
.rm-confirm .e-footer-content .e-btn { margin: 0; }
.e-btn.rm-confirm__cancel { background: var(--surface); border-color: var(--border); color: var(--ink); }
.e-btn.rm-confirm__go,
.e-btn.rm-confirm__go:hover,
.e-btn.rm-confirm__go:focus { background: var(--danger); border-color: var(--danger); color: #fff; }
.e-btn.rm-confirm__go:focus-visible { box-shadow: 0 0 0 3px rgba(162, 25, 31, .3); }

@media (max-width: 480px) {
    .rm-confirm .e-footer-content .e-btn { flex: 1 1 100%; height: 44px; }
}

/* Tabs */
.e-tab { font-family: var(--font); }
.e-tab .e-tab-header { background: transparent; border-bottom: 1px solid var(--border); }
.e-tab .e-tab-header::before { display: none; }
.e-tab .e-tab-header .e-toolbar-item .e-tab-wrap { padding: 10px 4px; }
.e-tab .e-tab-header .e-toolbar-item .e-tab-text {
    font-size: 13px; font-weight: 500; letter-spacing: 0;
    color: var(--muted); text-transform: none;
    padding: 0 14px;
}
.e-tab .e-tab-header .e-toolbar-item:hover .e-tab-text { color: var(--ink); }
.e-tab .e-tab-header .e-toolbar-item.e-active .e-tab-text { color: var(--blue); font-weight: 600; }
.e-tab .e-tab-header .e-indicator { background: var(--blue); height: 2px; }
.e-tab .e-content { padding-top: 16px; }

/* Pager */
.e-pager {
    background: var(--bg-tint-2);
    border-top: 1px solid var(--border);
    padding: 8px 14px;
    font-family: var(--font);
    font-size: 12.5px;
    color: var(--muted);
}
.e-pager .e-pagercontainer { background: transparent; border: 0; }
.e-pager .e-pagercontainer .e-numericitem,
.e-pager .e-pagercontainer .e-first,
.e-pager .e-pagercontainer .e-prev,
.e-pager .e-pagercontainer .e-next,
.e-pager .e-pagercontainer .e-last {
    background: transparent;
    border: 0;
    color: var(--ink);
    min-width: 28px; height: 28px; line-height: 28px;
    padding: 0 6px;
    border-radius: 6px;
}
.e-pager .e-pagercontainer .e-numericitem:hover,
.e-pager .e-pagercontainer .e-first:hover,
.e-pager .e-pagercontainer .e-prev:hover,
.e-pager .e-pagercontainer .e-next:hover,
.e-pager .e-pagercontainer .e-last:hover { background: var(--info-tint); color: var(--info-ink); }
.e-pager .e-pagercontainer .e-currentitem,
.e-pager .e-pagercontainer .e-currentitem:hover {
    background: var(--blue) !important;
    color: #fff !important;
    font-weight: 600;
}

/* Tooltip */
.e-tooltip-wrap.e-popup {
    background: var(--ink) !important;
    border: 0 !important;
    border-radius: 6px !important;
    box-shadow: var(--shadow) !important;
}
.e-tooltip-wrap .e-tip-content {
    font-family: var(--font) !important;
    font-size: 12px !important;
    color: #fff !important;
    padding: 6px 10px !important;
    line-height: 1.4;
}

/* Toast */
.e-toast-container .e-toast {
    font-family: var(--font);
    border-radius: var(--radius-sm);
    border: 1px solid var(--border);
    box-shadow: var(--shadow);
    background: #fff;
    padding: 12px 14px;
}
.e-toast-container .e-toast .e-toast-title { font-weight: 600; color: var(--ink); font-size: 13px; }
.e-toast-container .e-toast .e-toast-content { font-size: 12.5px; color: var(--muted); }
.e-toast-container .e-toast.e-toast-success { border-left: 3px solid var(--ok); }
.e-toast-container .e-toast.e-toast-info    { border-left: 3px solid var(--blue); }
.e-toast-container .e-toast.e-toast-warning { border-left: 3px solid var(--warn); }
.e-toast-container .e-toast.e-toast-danger,
.e-toast-container .e-toast.e-toast-error   { border-left: 3px solid var(--danger); }

/* ---- the grid the fields sit in ---- */

.rm-form-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 2px 18px; }
/* One field per row. A credential form is read and typed straight down —
   current, then new, then the same new again — and the pair that has to match
   belongs under itself rather than beside itself, where one box gets filled
   and the other missed. Capped: a password box the width of a desk is not
   easier to type into. */
.rm-form-grid--1 { grid-template-columns: minmax(0, 1fr); max-width: 30rem; }

.rm-form-grid--3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
.rm-form-grid--4 { grid-template-columns: repeat(4, minmax(0, 1fr)); }

.rm-form-grid .rm-field { margin-bottom: 12px; }

.rm-field--span-2 { grid-column: span 2; }
.rm-field--span-3 { grid-column: span 3; }
.rm-field--span-all { grid-column: 1 / -1; }

/* A multi-line box that anchors a column while short fields fill the cells
   beside it, rather than leaving a ragged gap under it. */
.rm-field--tall { grid-row: span 2; }
.rm-field--tall .rm-field-control,
.rm-field--tall textarea { height: calc(100% - 24px); }

/* ---- how it narrows ----

   These pages are read on a desk, on a tablet at reception, and now and
   then on a phone in a corridor, and the grid sheds columns on the way
   down.

   By the viewport rather than by the card, which is the second answer
   here. A container query measures the space a form actually has, which
   is the better question — but `container-type` applies layout
   containment, and containment makes the card a containing block for
   everything positioned inside it. Syncfusion's dropdowns compute their
   popup's position from that chain and land somewhere else entirely: a
   popup nobody can see, over a form nobody can click, on CI and not on
   the machine it was written on. The sidebar is a fixed width, so the
   viewport answers the same question one subtraction later.

   A span is clamped, never left dangling: a field asking for three
   columns of a two-column grid takes the row. Left as "span 3" it would
   force a third track the grid does not have and push the form off the
   side of the screen. */

/* Below a 1280 laptop: at 1280 itself the content beside the menu still takes four columns of 230px, which the
   forms rule needs. */
@media (max-width: 1279px) { .rm-form-grid--4 { grid-template-columns: repeat(3, minmax(0, 1fr)); } }

@media (max-width: 1100px) {
    .rm-form-grid--3,
    .rm-form-grid--4 { grid-template-columns: 1fr 1fr; }

    .rm-field--span-3 { grid-column: 1 / -1; }
}

@media (max-width: 720px) {
    .rm-form-grid,
    .rm-form-grid--3,
    .rm-form-grid--4 { grid-template-columns: 1fr; }

    .rm-field--span-2,
    .rm-field--span-3 { grid-column: auto; }

    .rm-field--tall { grid-row: auto; }
    .rm-field--tall .rm-field-control,
    .rm-field--tall textarea { height: auto; }
}

/* Groups are what survive the collapse. Once every field is stacked, the
   only thing left saying where one purpose ends and the next begins is
   the heading between them, so it keeps its rule and its air at every
   width rather than being trimmed as decoration on a small screen. */
.rm-form-grid + .rm-form-grid { margin-top: 4px; }
.rm-form-grid + .rm-section-title,
.rm-form-grid + .rm-section-header-row { margin-top: 18px; }

/* A list of routers has six columns whatever the screen is, and columns
   cannot be folded away without hiding a fact somebody came to read. So
   the table scrolls sideways inside its own card instead of pushing the
   page off the phone and taking every form with it. */
@media (max-width: 700px) {
    .console-table { display: block; overflow-x: auto; }
}

/* ---- the dashboard's chart ----

   Drawn as inline SVG rather than by a component: it has no script to run and
   nothing to initialise, so it renders the same in a browser, in a print and in
   a screenshot. The viewBox does the scaling; these rules only say what the
   ink looks like. */
.rm-chart { width: 100%; height: 220px; display: block; }

.rm-chart-label { font-size: 11px; fill: var(--muted); }

/* ---- a rendered document ----

   The onboarding instructions: somebody else's Markdown, rendered as HTML into
   a console that otherwise has no long-form prose in it. Read on a phone at the
   top of a stepladder as often as at a desk, so the measure is capped for the
   prose and released for the code — a wrapped command is a command typed
   wrongly, and the fenced blocks are what a person is actually copying. */
.rm-instructions { line-height: 1.55; }

.rm-instructions > p,
.rm-instructions > ul,
.rm-instructions > ol { max-width: 72ch; }

.rm-instructions h1 { font-size: 1.3rem; margin: 0 0 .75rem; }
.rm-instructions h2 { font-size: 1.1rem; margin: 1.75rem 0 .5rem; }
.rm-instructions h3 { font-size: .98rem; margin: 1.25rem 0 .35rem; }

.rm-instructions h2 {
    border-top: 1px solid var(--border);
    padding-top: 1rem;
}

.rm-instructions h2:first-of-type { border-top: 0; padding-top: 0; }

.rm-instructions pre {
    background: var(--bg-tint-2);
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
    padding: .7rem .8rem;
    overflow-x: auto;
    font-size: .85rem;
}

.rm-instructions code {
    font-size: .88em;
    overflow-wrap: anywhere;
}

.rm-instructions pre code { overflow-wrap: normal; }

.rm-instructions table {
    width: 100%;
    border-collapse: collapse;
    margin: .5rem 0 1rem;
    display: block;
    overflow-x: auto;
}

.rm-instructions th,
.rm-instructions td {
    text-align: left;
    padding: .45rem .5rem;
    border-bottom: 1px solid var(--border);
    vertical-align: top;
}

.rm-instructions hr {
    border: 0;
    border-top: 1px solid var(--border);
    margin: 1.5rem 0;
}

.rm-instructions blockquote {
    margin: 1rem 0;
    padding: .1rem 0 .1rem 1rem;
    border-left: 3px solid var(--accent);
    color: var(--ink-soft);
}

/* ---- the bar a page or a card is titled by ---- */

.rm-form-bar {
    display: flex;
    align-items: center;
    gap: 10px;
    flex-wrap: wrap;
    margin-bottom: 14px;
}

.rm-form-bar h2 { margin: 0; font-size: 1.05rem; font-weight: 800; }
.rm-form-bar .rm-form-actions { margin-left: auto; display: flex; gap: 8px; }

.rm-section-title {
    margin: 18px 0 8px;
    font-size: 13px;
    font-weight: 700;
    letter-spacing: .08em;
    text-transform: uppercase;
    color: var(--muted);
    border-top: 1px solid var(--border);
    padding-top: 14px;
}

.rm-section-title:first-child { border-top: 0; padding-top: 0; margin-top: 0; }

/* The heading and its help icon, together. space-between put the icon against
   the far edge of the card, yards from the words it explains — the same defect
   the pills were moved off for. It sits beside the heading, like rm-form-bar;
   anything that really belongs on the right asks for it with rm-form-actions. */
.rm-section-header-row {
    display: flex;
    align-items: center;
    gap: .5rem;
    margin-top: 1.25rem;
}

.rm-section-header-row .rm-form-actions { margin-left: auto; display: flex; gap: 8px; }

.rm-section-header-row > .rm-section-title { margin: 0; padding: 0; border: 0; }

/* ---- pills ---- */

.rm-pill {
    display: inline-flex;
    align-items: center;
    gap: .35rem;
    padding: 1px 10px;
    border-radius: 999px;
    font-size: 11px;
    line-height: 1.7;
    font-weight: 600;
    letter-spacing: .02em;
    background: var(--bg-tint-2);
    color: var(--ink-soft);
    vertical-align: middle;
}

.rm-pill .dot { width: 6px; height: 6px; border-radius: 50%; background: currentColor; }

.rm-pill--ok { background: #E7F3EC; color: var(--ok); }
.rm-pill--info { background: var(--bg-tint-2); color: var(--blue-deep); }
.rm-pill--warn { background: #FBF1E4; color: #6B4408; }
.rm-pill--err { background: #FBEAEA; color: var(--danger); }
.rm-pill--accent { background: #FBF1E4; color: #6B4408; }

/* An operator-only section on a page an organisation can also read. Named
   rather than styled inline, because "this part is not yours" has to look the
   same everywhere it appears or it teaches nobody anything. */
.rm-pill--operator { background: var(--accent); color: #fff; }

/* ---- the help icon (RmHelp) ----

   The same idea as .rm-field-hint-icon, one size up: a glyph rather than a
   line of text repeated on every card, read on hover or focus rather than
   read whether wanted or not. A card's explanation runs longer than a
   field's and sometimes carries a link, so this opens a real panel instead of
   a native title attribute, which cannot hold markup — and unlike the field
   icon, it is reachable by keyboard (tabindex is native to a <button>)
   because what it opens can itself contain something to click. */
.rm-help { position: relative; display: inline-block; margin: 0 0 .5rem; }

.rm-help__icon {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 16px;
    height: 16px;
    padding: 0;
    border: 1px solid var(--border);
    border-radius: 50%;
    background: var(--bg-tint-2);
    color: var(--ink-soft);
    font-style: italic;
    font-weight: 700;
    font-size: 10px;
    line-height: 1;
    cursor: help;
    transition: color .12s ease, border-color .12s ease;
}

.rm-help__icon:hover,
.rm-help__icon:focus-visible {
    color: var(--primary);
    border-color: var(--primary);
    outline: none;
}

/* display: none rather than opacity/visibility while closed, so a panel
   nobody has opened is not there to measure — an invisible panel positioned
   off a card's edge still counts toward the page's scroll width, which is
   exactly the phone-width overflow this stylesheet elsewhere goes out of its
   way to prevent. */
.rm-help__body {
    display: none;
    position: absolute;
    z-index: 30;
    top: 100%;
    left: 0;
    /* A width, not only a ceiling on one.

       An absolutely positioned box with no width is shrink-to-fit against its
       containing block, and the containing block here is the 16px icon — so
       the panel collapsed to its longest word and ran down the page as a
       column of one or two words, in front of the content, with the whole
       width of the screen beside it unused. */
    width: max-content;
    max-width: min(68ch, calc(100vw - 3rem));
    padding: .7rem .9rem;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
    box-shadow: var(--shadow);
    color: var(--ink-soft);
    font-size: .87rem;
    font-weight: 400;
}

.rm-help:hover .rm-help__body,
.rm-help:focus-within .rm-help__body { display: block; }

/* ---- classes the pages were already written against ----

   Every one of these appeared in the markup and in no stylesheet, so the
   element it was on rendered with the browser's own defaults. That is most of
   what "the forms look messy" was: an unstyled table, an unstyled fieldset
   with its grooved black border and notched legend, and a button marked as a
   link that was still a grey three-dimensional button.

   Defined rather than deleted, because they are in twenty files. The sweep
   replaces the uses; until it reaches a page, that page looks right anyway. */


/* A button that is an action rather than a submission. */
.link,
button.link {
    background: none;
    border: 0;
    padding: 0 .5rem 0 0;
    font: inherit;
    font-size: .87rem;
    color: var(--primary);
    cursor: pointer;
    text-decoration: none;
}

.link:hover { text-decoration: underline; }
.link.danger,
.link.bad { color: var(--danger); }

.section-title {
    margin: 18px 0 8px;
    font-size: 13px;
    font-weight: 700;
    letter-spacing: .08em;
    text-transform: uppercase;
    color: var(--muted);
}

.mono,
.key,
.reference {
    font-family: ui-monospace, SFMono-Regular, "Cascadia Mono", Menlo, Consolas, monospace;
    font-size: .85em;
}

.wording { color: var(--ink-soft); }

/* A fieldset with no chrome of the browser's own. The default is a grooved
   border with a notch cut out of it for the legend, drawn in the browser's
   colour rather than ours — which is the odd black shape around a form's
   title. Nothing on this console wants it. */
fieldset {
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
    padding: .9rem 1rem;
    margin: 1rem 0 0;
}

fieldset > legend {
    padding: 0 .4rem;
    font-size: .72rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: .06em;
    color: var(--muted);
}

/* The user guides.
   
   Everything .rm-instructions does, plus the two things a guide has that the
   onboarding text does not: screenshots, and tables that are read rather than
   sorted. The pictures are console screenshots, so they are wide — bounded to
   the column and given a border, because a screenshot of a white page against
   a white page has no edge and reads as part of the guide's own layout. */
.rm-guide img {
    display: block;
    max-width: 100%;
    height: auto;
    margin: 1rem 0;
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
}

.rm-guide table {
    border-collapse: collapse;
    margin: 1rem 0;
    width: 100%;
    max-width: 72ch;
    font-size: .93rem;
}

.rm-guide th,
.rm-guide td {
    border: 1px solid var(--border);
    padding: .45rem .6rem;
    text-align: left;
    vertical-align: top;
}

.rm-guide th { background: var(--bg-tint-2); font-weight: 600; }

/* The download line above the guide: a button and a sentence saying what it is
   for, on one baseline. */
.rm-guide-actions {
    display: flex;
    align-items: center;
    gap: .75rem;
    flex-wrap: wrap;
    margin: 0 0 1rem;
}

/* The routers page's certificate cell: a pill and the question mark that opens
   the detail, on one baseline. The column used to stack five facts and wrap
   them; it carries one now, and the rest is in a dialog. */
.rm-cert-cell {
    display: inline-flex;
    align-items: center;
    gap: .4rem;
}

/* A router's own settings (D99, D100), as a second line under how it
   authenticates: a label, the walled-garden pill and the button that opens
   the dialog. Wraps inside the cell rather than widening the column. */
.rm-router-settings {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: .3rem;
    margin-top: .35rem;
    font-size: .8rem;
}

/* Whether we can reach the router at all (§11.2), as a third line in the same
   cell. Its own class rather than a second pill inside .rm-router-settings:
   that would be the pill other tests and other eyes find first, and this
   answers a different question from the walled garden's. */
.rm-router-tunnel {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: .3rem;
    margin-top: .25rem;
    font-size: .8rem;
}

/* One line per certificate, and none of them wraps. These are host names,
   dates and identities — a name broken across two lines is a name somebody
   mistypes — so the table scrolls sideways instead, which is what every wide
   thing in this console does. */
.rm-cert-table { overflow-x: auto; }
.rm-cert-table .console-table { white-space: nowrap; }

/* A guest's record (D69): the tags on it as pills, each with its own remove
   button, and the notes as a dated list. The pill's form sits inline so the
   button reads as part of the tag rather than a row of its own. */
.rm-tag-list {
    list-style: none;
    display: flex;
    flex-wrap: wrap;
    gap: .5rem;
    padding: 0;
    margin: 0 0 1rem;
}
.rm-tag-list .rm-status-pill { display: inline-flex; align-items: center; gap: .4rem; }
.rm-inline { display: inline; margin: 0; }

/* The tags a guest has not got, as buttons: one press puts one on. Outlined
   rather than filled so the row reads as an offer, not as tags already
   applied — the two lists sit one above the other. */
.rm-tag-add-label { margin: 0 0 .35rem; font-size: 12px; }
.rm-tag-list--available { margin-bottom: 1rem; }
button.rm-tag-add {
    border: 1px dashed var(--border);
    background: transparent;
    color: var(--ink-soft);
    font: inherit;
    font-size: 11px;
    font-weight: 600;
    letter-spacing: .02em;
    cursor: pointer;
}
button.rm-tag-add:hover { border-style: solid; border-color: var(--primary); color: var(--primary); }
.rm-note-list { list-style: none; padding: 0; margin: 0 0 1rem; }
.rm-note-list li { padding: .5rem 0; border-bottom: 1px solid var(--border); }
.rm-note-text { white-space: pre-wrap; }

/* The line under a list that pages at the query rather than in the grid: what
   is on screen on the left, the way to the rest on the right. The grid's own
   pager moves within the window; these move the window. */
.rm-pager { margin-top: .5rem; align-items: baseline; }
.rm-pager p { margin: 0; }

/* ---- CRM additions: the language switch in the header, breadcrumbs, the message slot ---- */

.console-header-right { display: flex; align-items: center; gap: 1rem; }
.console-password { text-decoration: none; }
.console-password-icon { display: none; }
/* On a phone the header has no room for the words; the key stands for them. */
@media (max-width: 720px) {
    .console-header-right { gap: .6rem; }
    .console-password-text { display: none; }
    .console-password-icon { display: inline; font-size: 1.1rem; }
}
.console-language { background: var(--ink-soft); color: #fff; border: 1px solid #456; border-radius: 8px; padding: .2rem .5rem; font: inherit; font-size: .85rem; }
.rm-breadcrumb { font-size: .85rem; color: var(--muted); margin-bottom: .35rem; display: flex; gap: .4rem; flex-wrap: wrap; }
.rm-breadcrumb a { color: var(--blue); text-decoration: none; }
.rm-breadcrumb__here { color: var(--ink); font-weight: 600; }
.message { margin: .75rem 0; padding: .6rem .9rem; border-radius: var(--radius-sm); }
.message:empty { display: none; }
.message.ok { background: var(--ok-tint); color: var(--ok); border: 1px solid #BFE3CF; }
.visually-hidden { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }
.rm-thread { display: flex; flex-direction: column; gap: .5rem; }
.rm-bubble { max-width: 70%; padding: .6rem .9rem; border-radius: var(--radius-sm); background: var(--bg-tint-2); }
.rm-bubble--host { align-self: flex-end; background: #DCEBF7; }
.rm-bubble--system { align-self: center; background: transparent; color: var(--muted); font-size: .85rem; }
.rm-bubble--draft { border: 1px dashed var(--accent); background: #FFF7EC; }
.rm-bubble .meta { display: block; font-size: .75rem; color: var(--muted); margin-top: .25rem; }
.rm-window { font-size: .8rem; }

/* ---- the onboarding wizard (Arc 9): the type choice and the ordered steps ---- */
.rm-choice { padding: 1rem; }
.rm-steps { list-style: none; margin: 1rem 0 0; padding: 0; counter-reset: step; }
.rm-steps li { border-top: 1px solid var(--border); padding: .9rem 0; counter-increment: step; }
.rm-steps li > .rm-form-bar > div:first-child::before { content: counter(step) ". "; color: var(--muted); font-weight: 600; }
.rm-steps li.is-done { opacity: .72; }
.rm-steps li.is-next { background: var(--surface); border-radius: var(--radius-sm); padding-left: .6rem; padding-right: .6rem; }

/* ============================================================
   Layout pass, 2026-10-24: every console page against the forms rule.
   ============================================================ */

/* A group heading inside a card is the small muted rule Hotspot draws, whatever its element: `.card h2` outranked
   `.rm-section-title` and drew "ADD SITE" as a second page title. */
.card h2.rm-section-title,
.card h3.rm-section-title {
    font-size: 13px;
    font-weight: 700;
    letter-spacing: .08em;
    margin: 18px 0 8px;
}

.card h2.rm-section-title:first-child,
.card h3.rm-section-title:first-child,
.rm-editor > .rm-section-title:first-of-type { margin-top: 0; border-top: 0; padding-top: 0; }

/* A native time or date input, or a select, that carries Syncfusion's e-input class without its input group: the
   card rules above exclude e-* and Syncfusion's own skin needs the group, so it fell back to a dark browser box.
   Drawn as the Syncfusion box beside it, at its height. */
.rm-field-control input.e-input[type="time"],
.rm-field-control input.e-input[type="date"],
.rm-field-control input.e-input[type="datetime-local"],
.rm-field-control select.e-input,
.rm-field-control select:not([class*="e-"]) {
    width: 100%;
    /* Syncfusion's input box at this theme and density. */
    height: 32px;
    padding: 0 12px;
    font: inherit;
    font-size: 14px;
    color: var(--ink);
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
    box-shadow: none;
}

.rm-field-control input.e-input[type="time"]:hover,
.rm-field-control input.e-input[type="date"]:hover,
.rm-field-control input.e-input[type="datetime-local"]:hover,
.rm-field-control select.e-input:hover,
.rm-field-control select:not([class*="e-"]):hover { border-color: var(--blue); }

.rm-field-control input.e-input[type="time"]:focus,
.rm-field-control input.e-input[type="date"]:focus,
.rm-field-control input.e-input[type="datetime-local"]:focus,
.rm-field-control select.e-input:focus,
.rm-field-control select:not([class*="e-"]):focus {
    outline: none;
    border-color: var(--blue);
    box-shadow: 0 0 0 3px rgba(10, 115, 185, .12);
}

.rm-field-control input.e-input:disabled,
.rm-field-control select:disabled { background: var(--bg-tint-2); color: var(--ink); opacity: 1; }

/* A checkbox in a grid cell sits on the control's line, level with the inputs beside it, not under their labels. */
.rm-field-control > .check { min-height: 32px; display: flex; align-items: center; margin: 0; }
.rm-field-control > .check input { margin-top: 0; }

/* The editor in the list's place (Mark, 2026-10-24): the page title names the record, the bar holds Cancel then
   Save on the right, and the form's groups sit in one card. */
.rm-editor { margin-bottom: 0; }
.rm-editor .rm-form-grid { margin-bottom: 4px; }
.rm-editor .rm-section-title + .rm-form-grid { margin-top: 0; }

/* A group heading that carries its own controls: the heading, a choice that governs the group, and the group's Add. */
.rm-section-header-row.rm-conditions-head { display: flex; align-items: center; gap: 10px; border-top: 1px solid var(--border); padding-top: 14px; margin: 18px 0 8px; }
.rm-inline-label { font-size: 12px; color: var(--muted); font-weight: 500; margin-left: 8px; }
.rm-section-header-row select.rm-inline-select { width: auto; min-width: 12rem; height: 32px; padding: 0 10px; font: inherit; font-size: 14px; color: var(--ink); background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius-sm); }

/* A repeated row (a segment's condition, a playbook's step): its fields in the grid and its Remove at the row's end,
   on the controls' line. */
.rm-condition { display: flex; align-items: flex-end; gap: 12px; padding: 4px 0; border-bottom: 1px dashed var(--border); }
.rm-condition > .rm-form-grid { flex: 1 1 auto; margin: 0; }
.rm-condition > .rm-condition-remove { flex: 0 0 auto; margin-bottom: 14px; }
.rm-condition:last-of-type { border-bottom: 0; }

/* A set of checkboxes that belong together, side by side on the control's line and wrapping as a set. */
.rm-check-row { display: flex; flex-wrap: wrap; gap: 6px 22px; align-items: center; min-height: 32px; }
.rm-check-row > .check { margin: 0; align-items: center; }
.rm-check-row > .check input { margin-top: 0; }

/* A dialog's own buttons: secondary first, the action last, on the right, as the confirm dialog has them. */
.rm-dialog-actions { display: flex; justify-content: flex-end; gap: 8px; }

/* Tabs inside an editor card: the tab strip on the card's top, the content under it. */
.rm-editor .rm-tabs > .e-content { padding-top: 14px; }
.rm-steps-head { display: flex; justify-content: flex-end; margin: 0 0 6px; }

/* An editor's long text (a template's body) takes the height the card has to spare. */
.rm-editor .rm-field--tall textarea.e-input,
.rm-editor .rm-field--tall .e-multi-line-input textarea { min-height: 150px; }

/* A command's heading row (rule 7): the group's name, and the buttons that act on it on the right. */
.rm-section-header-row.rm-card-head { margin: 0 0 8px; }
.rm-section-header-row.rm-card-head .rm-form-actions { margin-left: auto; display: flex; gap: 8px; }

/* A one-row form's buttons in the row's last cell, on the controls' line. */
.rm-field--action .rm-field-control { display: flex; gap: 8px; align-items: center; min-height: 32px; }
.rm-field--action .rm-field-control > .e-btn { width: auto; }

/* A heading that sits straight above its own row (no buttons beside it) keeps the card's top clear of a rule. */
.card > form > h2.rm-section-title:first-child { margin-top: 0; border-top: 0; padding-top: 0; }

/* What a key may do: each module's choices as a small group, the groups flowing into columns. */
.rm-scope-picker { columns: 3 16rem; column-gap: 24px; }
.rm-scope-group { break-inside: avoid; margin: 0 0 12px; padding: 8px 12px 4px; border: 1px solid var(--border); border-radius: var(--radius-sm); }
.rm-scope-group legend { padding: 0 4px; font-size: .72rem; font-weight: 700; letter-spacing: .06em; text-transform: uppercase; color: var(--muted); }
.rm-scope-group .check { margin: 0 0 6px; font-size: 13px; line-height: 1.35; }
.rm-scope-group .check input { margin-top: 2px; }
.rm-scope-head { margin-top: 14px; }

/* Finding a guest by the address staff have: channel, address and Find on one line; once found, a line saying who. */
.rm-guest-search { display: grid; grid-template-columns: 9rem minmax(0, 1fr) auto; gap: 8px; align-items: center; }
.rm-guest-found { display: flex; align-items: center; gap: 10px; min-height: 32px; padding: 0 10px; border: 1px solid var(--border); border-radius: var(--radius-sm); background: var(--bg-tint-2); }
.rm-guest-found-text { flex: 1 1 auto; font-size: 13px; color: var(--ink); }
.rm-guest-missing { margin: 6px 0 0; font-size: 12px; color: var(--danger); }

/* A key made of a fixed prefix and a short name: the prefix sits in the box's front, the name is typed after it. */
.rm-key-input { display: flex; align-items: stretch; }
.rm-key-input > .rm-key-prefix { display: flex; align-items: center; padding: 0 8px; border: 1px solid var(--border); border-right: 0; border-radius: var(--radius-sm) 0 0 var(--radius-sm); background: var(--bg-tint-2); color: var(--muted); font-family: ui-monospace, Consolas, monospace; font-size: 13px; }
.rm-key-input > .e-input-group { border-top-left-radius: 0 !important; border-bottom-left-radius: 0 !important; flex: 1 1 auto; }
.rm-readonly-value { display: flex; align-items: center; min-height: 32px; padding: 0 12px; border: 1px solid var(--border); border-radius: var(--radius-sm); background: var(--bg-tint-2); color: var(--ink); font-size: 14px; }

/* A group heading that follows the editor's first, unheaded row keeps its rule above it. */
.rm-editor > .rm-form-grid ~ .rm-section-title { border-top: 1px solid var(--border); padding-top: 14px; margin-top: 18px; }
