/*
 * pp.css — this site's own styles.
 *
 * Loaded by MasterPage-DMX.master AFTER /shared-meta2/dist/css/main.min.css, so anything here
 * overrides the shared stylesheet without needing !important.
 *
 * Custom CSS belongs here rather than in a <style> block on a page. The shared stylesheet is
 * mounted by digitalmedia.cz and rhinocad.cz too and cannot be rebuilt for this host alone, so
 * this file is where portal-specific styling lives.
 *
 * Everything uses Bootstrap theme tokens (--bs-*) rather than literal colours, so it keeps
 * working if the site's dark mode is ever switched on.
 *
 * Contents
 *   1. Page shell           .pp-container, #pp-content
 *   2. Tiles                .pp-card
 *   3. Admin search + table .ad-*, #ad-results
 *   4. Editor modals        .pp-editor
 *   5. Form fields          .pp-editor, .pp-form
 *   6. API log              .log-*
 *   7. Order fold-out       .pp-recent-*, .order-detail
 *   8. Markdown editor      .md-*        (assets/js/dmx-markup-editor.js)
 *   9. Sales ticket form    .st-*        (/sales-ticket/)
 */


/* ------------------------------------------------------------------ *
 * 1. Page shell
 *
 * Every gated page hides its content until the role check passes, then reveals #pp-content in
 * the gate callback. Keeping the initial hidden state in CSS means the content is never painted
 * before the check runs.
 * ------------------------------------------------------------------ */

.pp-container { min-height: 70vh; }
#pp-content { display: none; }


/* ------------------------------------------------------------------ *
 * 1b. Anchor-based buttons stayed unreadable on hover
 *
 * A VISITED <a class="btn"> went blank on hover — the background filled in but the label kept
 * the button's resting colour. On .btn-outline-secondary those are both #6c757d, so the button
 * became an empty grey pill: the back arrows, the Uživatelé/Firmy cross-links, the editors'
 * Cancel links. The <button> ones inside the modals were never affected.
 *
 * The cause is in the shared stylesheet, `a.btn:visited { color: var(--bs-btn-color) }`
 * (src/styles/_body.scss). At (0,2,1) it outranks Bootstrap's own `.btn:hover` at (0,2,0), so
 * once a link had been visited its hover colour never applied. .btn-outline-primary and
 * .btn-outline-white escaped only because they carry per-variant :hover rules with !important.
 *
 * FIXED UPSTREAM by excluding the interactive states there. This stays as the local guarantee:
 * /shared-meta2/ is a virtual directory deployed from its own repo, on its own schedule, and is
 * also served to digitalmedia.cz and rhinocad.cz — this site must not go unreadable if that
 * upload lands later or is rolled back. Remove it once the shared fix is confirmed live.
 *
 * !important, not specificity, is what does the work here: an important declaration beats a
 * normal one whatever the selectors weigh, which is how a (0,2,0) selector overrules the
 * (0,2,1) one upstream. Deliberately NOT written as `a.btn:visited:hover { color: var(...) }` —
 * neater on paper, but declarations in a :visited rule are restricted by the browser and a
 * custom property resolved inside one is not something to bet a legible page on. This form is
 * the one confirmed working on the live site.
 *
 * Worth knowing if this ever comes back: getComputedStyle reports the UNVISITED colour for
 * :visited styles, as a privacy measure. It will tell you the text is #fff while the screen
 * shows grey. Only the rendered pixels can be trusted here.
 * ------------------------------------------------------------------ */

.btn-outline-secondary:hover,
.btn-outline-secondary:focus,
.btn-outline-secondary:focus-visible,
.btn-outline-secondary:active,
.btn-outline-secondary:hover *,
.btn-outline-secondary:focus *,
.btn-outline-secondary:focus-visible *,
.btn-outline-secondary:active * {
    color: #fff !important;
}
.btn-outline-secondary:hover,
.btn-outline-secondary:focus,
.btn-outline-secondary:focus-visible,
.btn-outline-secondary:active {
    background-color: #6c757d;
    border-color: #6c757d;
}


/* ------------------------------------------------------------------ *
 * 2. Tiles — the navigation cards on / and /admin/
 * ------------------------------------------------------------------ */

.pp-card {
    background: var(--bs-body-bg);
    border: 1px solid var(--bs-border-color);
    border-radius: 0.75rem;
    padding: 1.5rem;
    height: 100%;
    transition: border-color .15s ease, box-shadow .15s ease;
}
.pp-card:hover { border-color: var(--bs-primary); box-shadow: 0 .25rem .75rem rgba(0, 0, 0, .06); }
.pp-card .bi { font-size: 1.6rem; }

/* A BUTTON inside a card is not a tile, and its icon is not the tile's glyph.
 *
 * The rule above sizes a navigation tile's icon — a large standalone mark the tile leads with.
 * It reaches the icons inside the order buttons on / as well, which blows them up to 1.6rem
 * beside 1rem text: the icon then sets the line box, and the label sits low against an
 * oversized neighbour. Two fixes, and both are needed.
 *
 *   1em          the icon labels a line of text, so it takes that text's size
 *   inline-flex  centres the icon and the label ON EACH OTHER. Left inline, they align on a
 *                text baseline, and a glyph whose box is taller than the text always rides
 *                high off it — which is what this looked like even at matching sizes.
 *
 * Scoped to .btn so the card's own heading icon keeps the 1.6rem it is meant to have. */
.pp-card .btn { display: inline-flex; align-items: center; }
.pp-card .btn .bi { font-size: 1em; line-height: 1; }


/* ------------------------------------------------------------------ *
 * 3. Admin search and results table — /admin/user/, /admin/company/
 * ------------------------------------------------------------------ */

/* --btn-w pins the search button and positions the clear control from the same value, so the
   two cannot drift apart. !important because the shared site CSS styles .btn more specifically
   than a plain class selector can beat. */
.ad-search {
    max-width: 560px;
    position: relative;
    --btn-w: 3.25rem;
}
.ad-search .btn-search {
    width: var(--btn-w) !important;
    flex: 0 0 var(--btn-w) !important;
    padding-left: 0 !important;
    padding-right: 0 !important;
}
.ad-search .form-control { padding-right: 2.4rem; }

/* A box with no button beside it (/admin/administrator/, /admin/reseller/ — their reload lives in
   the page header). Zeroing --btn-w is all it takes: the clear control is positioned from that
   same value, so it moves back to the edge of the field instead of hanging in empty space. */
.ad-search-plain { --btn-w: 0rem; }

/* The clear control sits INSIDE the white field — as an input-group segment it renders as a
   bordered grey cell and reads like a third button, and over the blue button it disappears. */
.ad-clear {
    position: absolute;
    z-index: 5;
    right: calc(var(--btn-w) + .35rem);
    top: 0;
    height: 100%;
    display: flex;
    align-items: center;
    padding: 0 .35rem;
    border: 0;
    background: transparent;
    box-shadow: none;
    color: var(--bs-secondary-color);
    font-size: 1.15rem;
    line-height: 1;
    cursor: pointer;
}
.ad-clear:hover { color: var(--bs-danger); }

/* Deliberately fainter than Bootstrap's default. Its --bs-secondary-color renders about
   rgb(88,92,95) here, which sits close enough to typed input to read as a value already in the
   field rather than as a hint about what to type. gray-500 puts clear air between the two.

   A literal colour at full opacity rather than a token at reduced opacity: opacity blends toward
   whatever is behind the field, so the same declaration would drift if the input ever sat on a
   tinted background.

   SEARCH BOXES ONLY, which is why this is a list rather than a rule on .form-control. In a search
   field the placeholder is a hint about what to type; in the editors it is often the value the
   field falls back to ("Název firmy jako text (bez vazby)"), and fading that would hide something
   the operator needs to read. The /new-order/ boxes are named individually because the wizard
   does not use .ad-search — its search fields are part of the step, not a toolbar. */
.ad-search .form-control::placeholder,
#pp-cust-email::placeholder,
#co-search-q::placeholder {
    color: #adb5bd;
    opacity: 1;
}

/* The three count columns (orders, licences, users) sit shoulder to shoulder at the right edge,
   and each is now an icon plus a number — without a gap the six glyphs read as one run and it
   stops being obvious which number belongs to which column. Applied on the left so the space
   falls BETWEEN them; .ad-nowrap on the cells is what stops an icon and its number splitting
   across two lines in the first place. */
#ad-results th.ad-count,
#ad-results td.ad-orders,
#ad-results td.ad-users { padding-left: 1.1rem; }

.ad-id { font-family: var(--bs-font-monospace); font-size: .78rem; }
.ad-nowrap { white-space: nowrap; }

/* Wider than a phone: the table scrolls inside its own container rather than forcing the page
   to scroll sideways. */
#ad-results table { font-size: .85rem; }
#ad-results th { white-space: nowrap; }
#ad-results td { vertical-align: top; }

/* Company rows open the editor; table-hover already supplies the highlight. */
#ad-results tbody tr { cursor: pointer; }

/* …except the Uživ. cell, which opens the company's user list instead. The row-wide pointer
   above would otherwise promise the editor across the whole row, including the one place that
   does something else. The count itself stays a pointer — it IS the control. */
#ad-results td.ad-users { cursor: default; }
/* The users count is a <button>, its two neighbours are <a>. Left alone, Bootstrap's .btn gives
   it vertical-align:middle, its own font-size, and a 1px TRANSPARENT border — which together sat
   its icon and number a pixel below the orders and licence columns and drew the glyphs a size
   larger. The border is the part that is easy to miss: invisible, but it still pushes the
   content down. These four declarations hand the button back to the table. */
#ad-results td.ad-users .ad-users-btn {
    vertical-align: baseline;
    font-size: inherit;
    line-height: inherit;
    border: 0;
}
#ad-results td.ad-users .ad-users-btn { cursor: pointer; text-decoration: none; }
#ad-results td.ad-users .ad-users-btn:hover { text-decoration: underline; }

/* The select column on /admin/reseller/. Width comes from the checkbox, not from a number: the
   header holds one too, so a fixed width would only be a guess at the same thing.

   The CELL is the hit target, not the 13px box inside it — see the click handler — so the
   padding is what makes the column clickable and must not be trimmed away. Like .ad-users and
   .ad-orders it does something other than open the editor, so it does not carry the row's
   pointer; the box supplies its own.

   vertical-align middle against the #ad-results td rule above, which tops every other cell: a
   checkbox aligned to the top of a two-line company name floats above the text it selects. */
#ad-results th.ad-select,
#ad-results td.ad-select {
    width: 1%;
    white-space: nowrap;
    vertical-align: middle;
    cursor: default;
}
/* The shared bundle scales every .form-check-input by 1.5 — a TRANSFORM, so it happens after
   layout: the control paints wider than the box it occupies and spills over whatever is beside
   it. Its margin-right: 1rem is what papers over that everywhere else, so zeroing the margin
   here — the obvious thing to write for a column that should be tight — brought the overlap
   straight back, which is what this rule got wrong the first time.

   Asking for the size as width/height with transform: none keeps the geometry honest, and the
   margin then belongs to nobody. Same fix, same reason, as the sector-filter radios in
   new-order/default.aspx and orders/new/default.aspx — see docs/NewOrder.md §6.7. Do not put
   margin: 0 back without the two lines above it.

   1.15em against the table's own .85rem lands at about 15-16px: a checkbox the size a checkbox
   is, rather than one sized for a form. */
#ad-results td.ad-select .form-check-input,
#ad-results th.ad-select .form-check-input {
    transform: none;
    width: 1.15em;
    height: 1.15em;
    margin: 0;
    vertical-align: middle;
    cursor: pointer;
}

/* The Obj. cell leaves the page for the order lookup, so like .ad-users it is not part of the
   row's editor click and must not carry the row's pointer. */
#ad-results td.ad-orders { cursor: default; }
#ad-results td.ad-orders .ad-orders-link { text-decoration: none; }
#ad-results td.ad-orders .ad-orders-link:hover { text-decoration: underline; }

/* The Firma cell on /admin/user/ leaves the page for the company search, so like the two above
   it is not part of the row's editor click. Same restraint as .ad-orders-link: underlining every
   company name would turn a column of plain text into a wall of blue. */
#ad-results td.ad-company { cursor: default; }
#ad-results td.ad-company .ad-company-link { text-decoration: none; }
#ad-results td.ad-company .ad-company-link:hover { text-decoration: underline; }

/* The user list is read-only, so its rows must not look clickable the way #ad-results does. */
.cu-table td { vertical-align: top; }


/* ------------------------------------------------------------------ *
 * 4. Editor modals — the company and user editors under /admin/
 *
 * Keyed off .pp-editor rather than an id: #co-modal is ALSO the company picker in /new-order/,
 * a different dialog on a different page, and an id selector here would silently restyle it.
 * A class also keeps the install-instructions dialog on the same master page untouched.
 * ------------------------------------------------------------------ */

/* Light grey ground, so the white inputs and the ARES panels read as raised off it. */
.pp-editor .modal-content { background-color: var(--bs-tertiary-bg); }
.pp-editor .modal-header,
.pp-editor .modal-footer { border-color: var(--bs-border-color); }

/* Inset panels (ARES lookup, ARES compare, the user's company block). They stood off a white
   modal; on the grey ground they need the opposite treatment or they disappear into it. A class
   rather than a list of ids, so a new panel picks the styling up by itself. */
.pp-editor .pp-panel { background-color: var(--bs-body-bg); }


/* ------------------------------------------------------------------ *
 * 5. Form fields — .pp-editor and .pp-form
 *
 * Field styling is not specific to the modals: the new-customer form in the order wizard is the
 * same kind of form and should not look like a different product. .pp-editor is the dialogs,
 * .pp-form is any page-level form that wants the same treatment.
 * ------------------------------------------------------------------ */

/* Labels sit back from the values they describe, without becoming as faint as the muted helper
   text underneath them. */
.pp-editor .form-label,
.pp-form .form-label {
    font-size: .82rem;
    color: var(--bs-emphasis-color, #343a40);
    opacity: .75;
    margin-bottom: .2rem;
    padding-left: .5rem;
}

/* Switch labels are .form-check-label, not .form-label — matched so the two kinds do not end up
   different sizes side by side. No left padding: these sit beside their toggle, not above an
   input, so an indent would push them away from the control they belong to. */
.pp-editor .form-check-label,
.pp-form .form-check-label {
    font-size: .82rem;
    color: var(--bs-emphasis-color, #343a40);
    opacity: .75;
    margin-bottom: 0;
}

/* Bootstrap lays a .form-check out as a floated input inside a left-padded block, so the label
   aligns on the text baseline rather than to the switch. At the reduced label size that reads as
   the text sitting low. Flex centring aligns the two properly; the float and the padding/margin
   pair Bootstrap uses to position the input have to be undone for it to take effect. */
.pp-editor .form-check.form-switch,
.pp-form .form-check.form-switch {
    display: flex;
    align-items: center;
    gap: .5rem;
    padding-left: 0;
    min-height: 0;
}
.pp-editor .form-check.form-switch .form-check-input,
.pp-form .form-check.form-switch .form-check-input {
    float: none;
    flex: 0 0 auto;
    margin-left: 0;
    margin-top: 0;
}

/* intlTelInput wraps the phone input in .iti and injects the country selector beside it. Its own
   stylesheet sets .iti{display:inline-block}, so the wrapper shrinks to its content: the field
   ends up narrower than its neighbours and the label sits beside it instead of above. Making the
   wrapper a block puts the phone field back on the same grid as every other input. */
.pp-form .iti,
.pp-editor .iti { display: block; }

/* The input inside must fill the wrapper, and keep the .form-control box so its height matches
   the fields around it — the plugin re-parents the element but leaves its classes alone. */
.pp-form .iti > .form-control,
.pp-form .iti > .iti__tel-input,
.pp-editor .iti > .form-control,
.pp-editor .iti > .iti__tel-input { width: 100%; }

/* The shared site stylesheet sets .form-type-tel{padding-top:1rem;padding-bottom:1rem}, which
   makes the phone field noticeably taller than every other .form-control (Bootstrap's is
   .375rem). Restored to the standard box so it lines up with the fields around it.

   Only the vertical padding is reset: intlTelInput sets padding-left inline to make room for the
   dial code, and overriding that would put the number underneath the flag. */
.pp-form .form-type-tel,
.pp-editor .form-type-tel {
    padding-top: .375rem;
    padding-bottom: .375rem;
}

/* The per-field validation message the wizard uses. Revealed purely by the sibling .is-invalid
   on the input, so an input and its message must stay siblings inside .form-item. */
.pp-form .input-label-error,
.input-label-error { color: var(--bs-danger); font-size: .8rem; margin: .25rem 0 0; display: none; }
.is-invalid ~ .input-label-error { display: block; }

/* Locked fields — set by PartnerPortal.lockField().

   Both forms that use this show locked and editable fields in the same grid: /new-order/
   step 1 completing a found customer, and the user editor filling gaps in a profile. Bootstrap's
   :disabled is a slightly greyer fill, which in this theme reads as "empty, not reached yet"
   rather than "you cannot change this" — so a locked field gets a distinctly flatter fill, a
   dashed border and a padlock beside its label. The dashed border is what carries the meaning
   when the page is printed or the fill is lost to a forced-colours mode.

   opacity stays 1: the value is the point of showing the field at all, so it must stay as
   readable as an editable one. */
.pp-form .form-control.pp-locked,
.pp-form .form-select.pp-locked,
.pp-editor .form-control.pp-locked,
.pp-editor .form-select.pp-locked {
    /* --bs-secondary-bg (#e9ecef), NOT --bs-tertiary-bg: the latter is #f8f9fa in this theme,
       a hair off the #fff of an editable field, so it reads as more editable rather than less.
       This is the same grey Bootstrap's own :disabled uses, kept explicitly because the rules
       below override that declaration anyway. */
    background-color: var(--bs-secondary-bg);
    border-style: dashed;
    border-color: var(--bs-secondary-border-subtle);
    color: var(--bs-secondary-color);
    opacity: 1;
    cursor: not-allowed;
    box-shadow: none;
}

/* A locked field is not being judged, so it must not carry validation state. Bootstrap paints
   .is-valid as a green tick inside the field, which on a value nobody can change is noise. */
.pp-form .pp-locked.is-valid,
.pp-form .pp-locked.is-invalid,
.pp-editor .pp-locked.is-valid,
.pp-editor .pp-locked.is-invalid { background-image: none; border-color: var(--bs-secondary-border-subtle); }

/* The country dropdown is a sibling button inside .iti, so disabling the input alone leaves it
   looking live. intlTelInput's setDisabled() adds the attribute; this matches the flat fill. */
.pp-form .iti:has(> .pp-locked) .iti__selected-country,
.pp-editor .iti:has(> .pp-locked) .iti__selected-country,
.pp-form .iti__selected-country[disabled],
.pp-editor .iti__selected-country[disabled] {
    background-color: var(--bs-secondary-bg);
    cursor: not-allowed;
}

/* A checkbox/switch that reports state rather than accepting input (the "customer is a company"
   switch on an existing customer). */
.pp-form .form-check-input.pp-locked,
.pp-editor .form-check-input.pp-locked { opacity: .65; cursor: not-allowed; }

/* The padlock. On the wrapper, because CSS cannot reach a label from its input — lockField()
   sets .pp-locked-field on .form-item, or on the column that holds the label. */
.pp-locked-field > .form-label::after,
.pp-locked-field > .form-check-label::after,
.pp-locked-field > .form-check > .form-check-label::after {
    content: "\F47A";                 /* bi-lock-fill; the font comes from main.min.css */
    font-family: bootstrap-icons;
    font-weight: normal;
    font-size: .78em;
    margin-left: .35rem;
    vertical-align: baseline;
    color: var(--bs-secondary-color);
}


/* ------------------------------------------------------------------ *
 * 6. API call log — /log/
 * ------------------------------------------------------------------ */

.log-row { border: 1px solid var(--bs-border-color); border-radius: .5rem; margin-bottom: .5rem; }
.log-head {
    display: flex;
    align-items: center;
    gap: .5rem;
    flex-wrap: wrap;
    padding: .5rem .75rem;
    cursor: pointer;
    background: var(--bs-body-bg);
}
.log-head:hover { background: var(--bs-tertiary-bg); }
.log-ts { font-variant-numeric: tabular-nums; white-space: nowrap; }
.log-ep { font-family: var(--bs-font-monospace); font-size: .8rem; word-break: break-all; }
.log-body { display: none; border-top: 1px solid var(--bs-border-color); padding: .75rem; }
.log-row.open .log-body { display: block; }
.log-body pre {
    background: var(--bs-tertiary-bg);
    border-radius: .375rem;
    padding: .6rem;
    font-size: .78rem;
    white-space: pre-wrap;
    word-break: break-word;
    max-height: 22rem;
    overflow: auto;
    margin: 0 0 .5rem 0;
}
.log-label { font-size: .72rem; text-transform: uppercase; letter-spacing: .04em; }


/* ------------------------------------------------------------------ *
 * 7. Order detail fold-out — the recent-orders table on /
 * ------------------------------------------------------------------ */

/* The rows open; table-hover already supplies the highlight. */
.pp-recent-row { cursor: pointer; }

/* Chevron scoped to this table on purpose: the order cards under /admin/*-orders/ turn a
   chevron-right a quarter turn, the licence pages turn a chevron-down a half turn, and a
   bare .chevron-icon rule here would reach into both. */
.pp-recent-row .chevron-icon { display: inline-block; transition: transform .2s ease; }
.pp-recent-row .chevron-icon.open { transform: rotate(90deg); }

/* The fold-out row is not itself clickable, so it must not light up with table-hover as if
   it were — and the highlight would sit on top of the panel's own ground. */
.pp-recent-detail:hover > * { --bs-table-bg-state: transparent; }

/* The install-instruction link in the fold-out is a bare icon — the button chrome it used to
   carry was doing nothing the glyph does not already say. Scoped to .ii-icon rather than to
   .js-install-link, because the order wizard's product tree renders the same link at body size
   and must not double with it. line-height keeps the larger glyph from stretching its row. */
.js-install-link.ii-icon { font-size: 200%; line-height: 1; }

/* The fold-out itself. The markup inside comes from OrderUtils.renderOrderInfo(), which is
   also what the order cards under /admin/*-orders/ render — those pages carry their own copy
   of these four rules in a page <style> block, so keep the two in step. */
.order-detail { background: var(--bs-tertiary-bg); border-top: 1px solid var(--bs-border-color); }
.order-detail .detail-row { display: flex; gap: .5rem; padding: .25rem 0; }
.order-detail .detail-label { color: var(--bs-secondary-color); min-width: 140px; font-size: .85rem; }
.order-detail .detail-value { font-size: .85rem; }


/* ------------------------------------------------------------------ *
 * 8. Markdown editor
 *
 * Drawn by assets/js/dmx-markup-editor.js around a plain <textarea>. The toolbar and the
 * preview are siblings of the textarea inside .md-editor, so the three share one border and
 * read as a single field rather than as a field with decorations above it.
 * ------------------------------------------------------------------ */

.md-editor {
	border: 1px solid var(--bs-border-color);
	border-radius: var(--bs-border-radius);
	overflow: hidden;
}

/* The field inside has already drawn the frame, so the textarea must not draw a second one —
   including the focus ring, which Bootstrap puts on the control rather than on its container. */
.md-editor .md-input,
.md-editor .md-input:focus {
	border: 0;
	border-radius: 0;
	box-shadow: none;
	resize: vertical;
}

.md-toolbar {
	display: flex;
	align-items: center;
	gap: .125rem;
	flex-wrap: wrap;
	padding: .25rem .375rem;
	background: var(--bs-tertiary-bg);
	border-bottom: 1px solid var(--bs-border-color);
}

.md-toolbar .md-btn {
	--bs-btn-padding-x: .5rem;
	--bs-btn-padding-y: .2rem;
	background: transparent;
	border-color: transparent;
	color: var(--bs-secondary-color);
}

.md-toolbar .md-btn:hover,
.md-toolbar .md-btn.active {
	background: var(--bs-body-bg);
	color: var(--bs-body-color);
}

/* Pushes the preview toggle to the far end, away from the formatting buttons — it does
   something of a different kind and should not read as one more of them. */
.md-spacer { flex: 1 1 auto; }

.md-preview {
	padding: .75rem;
	overflow-y: auto;
	background: var(--bs-body-bg);
}

/* The preview shows what YouTrack will show, so it is sized like prose and not like a form
   control. The last child's margin is dropped or the panel gains a phantom bottom gutter. */
.md-preview > :last-child { margin-bottom: 0; }
.md-preview h1, .md-preview h2, .md-preview h3 { font-size: 1.05rem; font-weight: 700; margin: .75rem 0 .35rem; }
.md-preview pre { background: var(--bs-tertiary-bg); padding: .5rem .75rem; border-radius: var(--bs-border-radius); overflow-x: auto; }
.md-preview code { font-size: .85em; }
.md-preview blockquote {
	border-left: 3px solid var(--bs-border-color);
	padding-left: .75rem;
	color: var(--bs-secondary-color);
	margin-bottom: .5rem;
}


/* ------------------------------------------------------------------ *
 * 9. Sales ticket form (/sales-ticket/)
 * ------------------------------------------------------------------ */

.st-drop {
	display: flex;
	align-items: center;
	justify-content: center;
	gap: .5rem;
	padding: 1.25rem;
	border: 1px dashed var(--bs-border-color);
	border-radius: var(--bs-border-radius);
	background: var(--bs-tertiary-bg);
	color: var(--bs-secondary-color);
	cursor: pointer;
	transition: border-color .15s ease, background-color .15s ease;
}

.st-drop:hover,
.st-drop:focus-visible,
.st-drop-over {
	border-color: var(--bs-primary);
	background: var(--bs-body-bg);
}

.st-drop .bi { font-size: 1.25rem; }

.st-file {
	display: flex;
	align-items: center;
	gap: .5rem;
	padding: .35rem .5rem;
	border-bottom: 1px solid var(--bs-border-color);
	font-size: .875rem;
}

/* A long file name must not push the size and the remove button off the row; it is the part
   that can afford to be cut. */
.st-file-name { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.st-file-size { color: var(--bs-secondary-color); white-space: nowrap; }
.st-file-remove { color: var(--bs-secondary-color); line-height: 1; }
.st-file-remove:hover { color: var(--bs-danger); }

/* Fixed width so the row does not resize as the bar appears and disappears. */
.st-file-progress { width: 5rem; height: .4rem; flex: 0 0 auto; }

.st-file-total {
	padding: .35rem .5rem;
	font-size: .8rem;
	text-align: right;
}

/* The ticket number is the one thing worth carrying away from the success panel. */
.st-done-icon { font-size: 3rem; line-height: 1; }
.st-issue-id {
	font-family: var(--bs-font-monospace);
	font-size: 1.5rem;
	font-weight: 700;
	color: var(--bs-primary);
}


/* ==========================================================================================
 * PRODUCT TREE — the lazy catalogue browser (orders/new/product-tree.js)
 *
 * Moved here 2026-09-22 from inline <style> blocks in new-order/default.aspx and
 * orders/new/default.aspx, which carried a copy each. They had already drifted: the
 * .pp-tier-group rule below existed only in new-order, so the innermost grouping level rendered
 * unstyled on /orders/new/. Three pages mount this tree now (the install-instruction index is
 * the third) and a fourth copy was not worth writing.
 *
 * product-tree.js depends on these class names. Both masters load pp.css, so a page that mounts
 * a tree needs no stylesheet of its own — only the page-specific chrome around it.
 * ========================================================================================== */
.pp-tree-list { list-style: none; margin: 0; padding: 0; }
.pp-children { padding-left: 1.5rem; border-left: 1px solid var(--bs-border-color); margin-left: .6rem; }
.pp-node-row { display: flex; align-items: center; gap: .25rem; padding: .2rem 0; }
.pp-caret {
    border: 0; background: transparent; width: 1.5rem; height: 1.5rem; flex: 0 0 1.5rem;
    display: inline-flex; align-items: center; justify-content: center; color: var(--bs-secondary);
    cursor: pointer; padding: 0; border-radius: .25rem;
}
.pp-caret:hover { background: var(--bs-secondary-bg); }
.pp-caret .bi { transition: transform .15s ease; }
.pp-node.pp-open > .pp-node-row > .pp-caret .bi { transform: rotate(90deg); }
.pp-caret-none { cursor: default; }
.pp-node-branch { cursor: pointer; font-weight: 500; }
.pp-node-branch:hover { color: var(--bs-primary); }
/* Level 1: vendor cards (horizontal) */
.pp-vendor-cards { display: flex; flex-wrap: wrap; gap: .75rem; margin-bottom: 1.25rem; }
.pp-vendor-card {
    display: flex; flex-direction: column; align-items: center; justify-content: center;
    gap: .5rem; min-width: 8.5rem; padding: 1rem 1.25rem;
    background: var(--bs-body-bg); border: 1px solid var(--bs-border-color);
    border-radius: .75rem; cursor: pointer; transition: border-color .15s ease, box-shadow .15s ease;
}
.pp-vendor-card:hover { border-color: var(--bs-primary); }
.pp-vendor-card.active { border-color: var(--bs-primary); box-shadow: 0 0 0 .2rem var(--bs-primary-bg-subtle); }
.pp-vendor-card-name { font-weight: 600; }
.pp-vendor-logo { height: 5rem; width: auto; }
/* ProductFamilyGroup icons in the tree */
.pp-node-group > .pp-node-row > .pp-node-name { display: inline-flex; align-items: center; gap: .4rem; }
.pp-group-icon { height: 3rem; width: auto; }
.pp-vendor-tree > .pp-tree-list > .pp-node-group { margin-bottom: 1rem; }
.pp-leaf { display: flex; align-items: center; gap: .5rem; margin: 0; cursor: pointer; font-weight: 400; }
.pp-sku { font-family: var(--bs-font-monospace); font-size: .72rem; }
/* One-month licences, set apart at a glance in a list that is otherwise annual. */
.pp-node-name.pp-term-monthly { font-style: italic; }
.pp-tree-loading, .pp-tree-empty, .pp-tree-error { padding: .3rem 0 .3rem 1.75rem; }
/* The loading line that stands in for the VENDOR CARDS, which is a different job from the
   one above: those sit in the tree's indented lists, this one holds a row's worth of
   space open. A card is a 5rem logo plus its name and padding, so the row lands at about
   8.75rem — without reserving it the spinner occupies one line and everything below jumps
   down when the logos arrive. Only ever one of these, so a flex row centred on itself. */
.pp-vendor-cards > .pp-tree-loading {
    display: flex; align-items: center; justify-content: center;
    width: 100%; min-height: 8.75rem; padding: 0;
}

/* Sector filter — "All" plus one radio per ProductLicSector, above the vendor logos. */
.pp-tree-filters { margin-bottom: .75rem; }
.pp-tree-filters:empty { margin-bottom: 0; }   /* no sectors to filter by: no gap either */
.pp-sector-filter {
    display: flex; flex-wrap: wrap; align-items: center; gap: .35rem 1.5rem;
    padding: .6rem .9rem; border: 1px solid var(--bs-border-color); border-radius: .5rem;
}
/* Bootstrap lays .form-check out for a STACKED list: block display, a left indent, and a
   negative margin tucking the input back into it. This is one inline row, so all of that
   is undone and the radio simply sits beside its label. */
.pp-sector-filter .pp-sector-radio {
    display: flex; align-items: center; gap: .5rem; margin: 0; padding: 0; min-height: 0;
}
/* The shared bundle scales every .form-check-input by 1.5 — a transform, so it happens
   AFTER layout: the control paints wider than the box it occupies and spills over its own
   label. Asking for the size as width/height instead keeps the geometry honest. Do not
   reintroduce `margin: 0` without this, or the overlap comes back (the bundle's
   margin-right: 1rem is what papers over it elsewhere). */
.pp-sector-filter .pp-sector-radio .form-check-input {
    transform: none; width: 1.4em; height: 1.4em;
    margin: 0; flex: 0 0 auto; cursor: pointer;
}
.pp-sector-filter .pp-sector-radio .form-check-label {
    margin: 0; cursor: pointer; font-size: .95rem; user-select: none;
}
.pp-sector-filter .pp-sector-radio .form-check-input:checked + .form-check-label { font-weight: 600; }
.pp-sector-filter .pp-sector-radio .form-check-input:not(:checked) + .form-check-label { color: var(--bs-secondary); }
/* Vendor with nothing left under the current filter: dimmed, but still clickable — the
   click is what shows the "change the filter" note. */
.pp-vendor-card-dim { opacity: .45; }
.pp-vendor-card-dim:hover, .pp-vendor-card-dim.active { opacity: .75; }
.pp-tree-nomatch { padding: .25rem 0 .25rem 1.75rem; }
.pp-vendor-cards.pp-busy { opacity: .5; pointer-events: none; }

/* Sector / licence-type grouping (collapsible) */
.pp-group-header {
    display: flex; align-items: center; gap: .25rem;
    padding: .2rem 0 .2rem 1rem; cursor: pointer; letter-spacing: .03em;
}
.pp-group-header:hover .pp-group-name { color: var(--bs-primary); }
.pp-group-name { cursor: pointer; }
.pp-sector-group > .pp-group-header > .pp-group-name { color: var(--bs-body-color); }
.pp-lictype-group > .pp-group-header > .pp-group-name { color: var(--bs-secondary); }
.pp-sector-group.pp-open > .pp-group-header > .pp-caret .bi,
.pp-lictype-group.pp-open > .pp-group-header > .pp-caret .bi { transform: rotate(90deg); }
.pp-group-items { padding-left: 1.5rem; }

/* Vendor licence type / subtype grouping (non-foldable static sections) */
.pp-static-header { padding: .15rem 0 .1rem 1rem; }
.pp-pvtype-group > .pp-static-header .pp-static-name { font-weight: 600; font-size: .85rem; }
.pp-pvsub-group > .pp-static-header .pp-static-name { font-weight: 500; font-size: .8rem; color: var(--bs-secondary); }
.pp-tier-group > .pp-static-header .pp-static-name { font-weight: 500; font-size: .78rem; color: var(--bs-secondary); font-style: italic; }
.pp-static-items { padding-left: 1.25rem; }

/* Link leaves (ProductTree opts.leafHref): the product name IS the way in, so the row reads as
   a link instead of a checkbox. Underline on hover only — a tree of several hundred underlined
   names is unreadable. */
.pp-leaf-link { text-decoration: none; }
.pp-leaf-link:hover .pp-node-name { text-decoration: underline; }
