/*
 * UmbPanel brand theme — overrides Portal Engine tokens. Load AFTER
 * portal-engine.css so these unlayered rules win over PE's @theme (layered)
 * and its unlayered :root chart palette.
 *
 * The customer portal runs dark by default (<html data-theme="dark">), so the
 * dark block is the effective palette; :root carries brand primary/fonts/radii
 * and a light fallback.
 */

/* Alliance fonts (self-hosted, served from /fonts). Full weight set mirrors
   the previous FrontEnd/src/scss/fonts/_fonts.scss. */
@font-face { font-family: 'AllianceNo.1'; src: url('/fonts/AllianceNo1Light/font.woff2') format('woff2'), url('/fonts/AllianceNo1Light/font.woff') format('woff'); font-weight: 300; font-style: normal; font-display: swap; }
@font-face { font-family: 'AllianceNo.1'; src: url('/fonts/AllianceNo1LightItalic/font.woff2') format('woff2'), url('/fonts/AllianceNo1LightItalic/font.woff') format('woff'); font-weight: 300; font-style: italic; font-display: swap; }
@font-face { font-family: 'AllianceNo.1'; src: url('/fonts/AllianceNo1Regular/font.woff2') format('woff2'), url('/fonts/AllianceNo1Regular/font.woff') format('woff'); font-weight: 400; font-style: normal; font-display: swap; }
@font-face { font-family: 'AllianceNo.1'; src: url('/fonts/AllianceNo1RegularItalic/font.woff2') format('woff2'), url('/fonts/AllianceNo1RegularItalic/font.woff') format('woff'); font-weight: 400; font-style: italic; font-display: swap; }
@font-face { font-family: 'AllianceNo.1'; src: url('/fonts/AllianceNo1Medium/font.woff2') format('woff2'), url('/fonts/AllianceNo1Medium/font.woff') format('woff'); font-weight: 500; font-style: normal; font-display: swap; }
@font-face { font-family: 'AllianceNo.1'; src: url('/fonts/AllianceNo1MediumItalic/font.woff2') format('woff2'), url('/fonts/AllianceNo1MediumItalic/font.woff') format('woff'); font-weight: 500; font-style: italic; font-display: swap; }
@font-face { font-family: 'AllianceNo.1'; src: url('/fonts/AllianceNo1SemiBold/font.woff2') format('woff2'), url('/fonts/AllianceNo1SemiBold/font.woff') format('woff'); font-weight: 600; font-style: normal; font-display: swap; }
@font-face { font-family: 'AllianceNo.1'; src: url('/fonts/AllianceNo1SemiBoldItalic/font.woff2') format('woff2'), url('/fonts/AllianceNo1SemiBoldItalic/font.woff') format('woff'); font-weight: 600; font-style: italic; font-display: swap; }
@font-face { font-family: 'AllianceNo.1'; src: url('/fonts/AllianceNo1Bold/font.woff2') format('woff2'), url('/fonts/AllianceNo1Bold/font.woff') format('woff'); font-weight: 700; font-style: normal; font-display: swap; }
@font-face { font-family: 'AllianceNo.1'; src: url('/fonts/AllianceNo1BoldItalic/font.woff2') format('woff2'), url('/fonts/AllianceNo1BoldItalic/font.woff') format('woff'); font-weight: 700; font-style: italic; font-display: swap; }
@font-face { font-family: 'AllianceNo.1'; src: url('/fonts/AllianceNo1ExtraBold/font.woff2') format('woff2'), url('/fonts/AllianceNo1ExtraBold/font.woff') format('woff'); font-weight: 800; font-style: normal; font-display: swap; }
@font-face { font-family: 'AllianceNo.1'; src: url('/fonts/AllianceNo1ExtraBoldItalic/font.woff2') format('woff2'), url('/fonts/AllianceNo1ExtraBoldItalic/font.woff') format('woff'); font-weight: 800; font-style: italic; font-display: swap; }
@font-face { font-family: 'AllianceNo.1'; src: url('/fonts/AllianceNo1Black/font.woff2') format('woff2'), url('/fonts/AllianceNo1Black/font.woff') format('woff'); font-weight: 900; font-style: normal; font-display: swap; }
@font-face { font-family: 'AllianceNo.1'; src: url('/fonts/AllianceNo1BlackItalic/font.woff2') format('woff2'), url('/fonts/AllianceNo1BlackItalic/font.woff') format('woff'); font-weight: 900; font-style: italic; font-display: swap; }
@font-face { font-family: 'AllianceNo.2Medium'; src: url('/fonts/AllianceNo2Medium/font.woff2') format('woff2'), url('/fonts/AllianceNo2Medium/font.woff') format('woff'); font-weight: 500; font-style: normal; font-display: swap; }

/* Brand tokens + light fallback surfaces. */
:root {
  --color-primary: #c7ea46;
  --color-primary-strong: #b3d63a;
  --color-primary-content: #0f172a;

  --color-positive: #c7ea46;
  --color-negative: #f9554c;
  --color-warning: #e9bc18;
  --color-info: #179faa;

  --color-surface: #ffffff;
  --color-surface-muted: #f1f5f9;
  --color-surface-raised: #ffffff;
  --color-on-surface: #0f172a;
  --color-on-surface-muted: #64748b;
  --color-border: #e2e8f0;
  --color-canvas: #f8fafc;

  --font-sans: 'AllianceNo.1', 'Segoe UI', system-ui, -apple-system, sans-serif;

  --radius-panel: 0.3rem;
  --radius-control: 0.2rem;

  /* Thinner buttons than PE's default 500 (pe-button reads this var). */
  --pe-button-weight: 400;

  --pe-chart-1: #c7ea46;
  --pe-chart-2: #438eff;
  --pe-chart-3: #179faa;
  --pe-chart-4: #f7649f;
  --pe-chart-5: #f1963b;
  --pe-chart-6: #5a58eb;
  --pe-chart-7: #e9bc18;
  --pe-chart-8: #64748b;
}

/* Dark palette — the customer portal's default. Values taken from the live
   site's resolved --tb-* dark tokens (Vixon dark mode, deep aubergine
   $body-bg-dark: #15001f). Cards are flat (surface == canvas) and separated by
   the purple border, exactly as the current site renders them. */
[data-theme='dark'] {
  --color-primary: #c7ea46;         /* lime */
  --color-primary-strong: #ddf290;  /* light lime (site link/hover) */
  --color-primary-content: #0f172a; /* dark text on lime */

  --color-positive: #c7ea46;        /* site: success == lime */
  --color-negative: #f9554c;
  --color-warning: #e9bc18;
  --color-info: #179faa;

  --color-canvas: #15001f;          /* aubergine page background */
  --color-surface: #0c0013;         /* cards sit DARKER than the page */
  --color-surface-muted: #1c0a26;   /* tertiary bg (input group, hover) — between card and page */
  --color-surface-raised: #1b0625;  /* overlays (modal/drawer) sit LIGHTER than the page so they don't get lost (live-site modal bg) */
  --color-on-surface: #d0ccd2;      /* body text */
  --color-on-surface-muted: #a199a5;/* secondary/muted text */
  --color-border: #291632;          /* purple border */

  --color-overlay: rgb(10 0 15 / 0.7);
}

/* Headings use Alliance No.2 Medium; colour is left to the library's utility
   classes (text-on-surface etc.) rather than forced here. */
h1, h2, h3, h4, h5, h6 {
  font-family: 'AllianceNo.2Medium', var(--font-sans);
}

/* Authenticated shell — brand chrome in the docked sidebar (logo + BETA and
   version badges). No library equivalent, so it lives with the brand theme. */
.portal-sidebar { width: 264px; }
.sidebar-brand { text-align: center; padding-bottom: 12px; margin-bottom: 8px; border-bottom: 1px solid var(--color-border); }
.sidebar-brand img { width: 180px; height: 55px; max-width: 100%; margin: 0 auto 12px; display: block; }
/* App-bar brand logo. Needs its own size rule: the height="28" attribute is
   overridden by the img reset's height:auto, and GetCropUrl can't resize an SVG,
   so without this the logo collapses to 0x0. width:auto keeps any brand's aspect. */
.topbar-logo img { height: 28px; width: auto; max-width: 100%; display: block; }
.brand-badges { display: flex; gap: 10px; justify-content: center; align-items: center; flex-wrap: wrap; }
.brand-badges a,
.brand-badges button { display: inline-flex; text-decoration: none; background: none; border: 0; padding: 0; margin: 0; cursor: pointer; font: inherit; color: inherit; }
.version-badge { position: relative; }
.version-badge .unread-dot { position: absolute; top: -3px; right: -3px; width: 8px; height: 8px; border-radius: 50%; background: var(--color-negative); box-shadow: 0 0 0 2px var(--color-surface); }

/* Umbraco Block Grid layout. The template's block-grid stylesheet went with
   Bootstrap, so restore the grid here — column spans, gaps and area columns come
   from the inline custom properties Umbraco sets on each element from the editor
   config; the fallbacks keep a sensible layout when a value is unset. */
.umb-block-grid__layout-container {
  display: grid;
  grid-template-columns: repeat(var(--umb-block-grid--grid-columns, 12), minmax(0, 1fr));
  gap: 1rem;
}
.umb-block-grid__layout-item {
  grid-column-end: span min(var(--umb-block-grid--item-column-span, 12), var(--umb-block-grid--grid-columns, 12));
  grid-row: span var(--umb-block-grid--item-row-span, 1);
}
.umb-block-grid__area-container {
  display: grid;
  grid-template-columns: repeat(var(--umb-block-grid--area-grid-columns, 12), minmax(0, 1fr));
  gap: 1rem;
}
.umb-block-grid__area {
  grid-column-end: span min(var(--umb-block-grid--area-column-span, 12), var(--umb-block-grid--area-grid-columns, 12));
  grid-row: span var(--umb-block-grid--area-row-span, 1);
}

/* Themed scrollbars via CSS (replacing the template's SimpleBar JS) — brand
   lime thumb on a transparent track, like umbhost.net. */
* {
  scrollbar-width: thin;
  scrollbar-color: var(--color-primary) transparent;
}
::-webkit-scrollbar { width: 10px; height: 10px; }
::-webkit-scrollbar-track { background: transparent; }
::-webkit-scrollbar-thumb { background-color: var(--color-primary); border-radius: 5px; }
::-webkit-scrollbar-thumb:hover { background-color: var(--color-primary-strong); }

/* Interactive KPI cards: a pe-panel wrapped in a link gets a hover lift. Only
   box-shadow transitions — transitioning border-color makes the border animate
   from the default light currentColor to the theme colour when the panel first
   upgrades, which reads as a white flash. */
a.block > pe-panel { transition: box-shadow .15s ease; }
a.block:hover > pe-panel { border-color: var(--color-primary); box-shadow: var(--shadow-panel); }

/* Vertical rhythm between the stacked content blocks in the page main column
   (announcement block-list, alert banners, the content block-grid). */
main > .umb-block-list,
main > .umb-block-grid,
main > pe-alert { display: block; margin-bottom: 1rem; }

/* Anti-FOUC: the lazy pe-* components render their raw children first and only
   lay out into cards/bars once their JS chunk upgrades them, which reflows the
   page. Keep the shell hidden (but laid out) while any key component on the page
   is still :not(:defined); the browser reveals it automatically once they're all
   upgraded — no JS. A 2s timeout in master.cshtml is the safety net. */
body:has(:is(pe-app-bar, pe-footer-bar, pe-nav, pe-breadcrumbs, pe-panel, pe-stat, pe-badge, pe-button, pe-alert, pe-data-table, pe-avatar, pe-icon):not(:defined)) .portal-shell {
  visibility: hidden;
}

/* Centered loading spinner over the canvas while the shell is cloaked. Hidden by
   CSS the moment all key pe-* components are defined (same condition as the
   cloak reveal); the 2s JS safety net in master.cshtml also hides it. */
.portal-loading { position: fixed; inset: 0; z-index: 9999; display: flex; align-items: center; justify-content: center; background: var(--color-canvas); }
.portal-spinner { width: 40px; height: 40px; border: 3px solid var(--color-border); border-top-color: var(--color-primary); border-radius: 50%; animation: portal-spin .8s linear infinite; }
@keyframes portal-spin { to { transform: rotate(360deg); } }
body:not(:has(:is(pe-app-bar, pe-footer-bar, pe-nav, pe-breadcrumbs, pe-panel, pe-stat, pe-badge, pe-button, pe-alert, pe-data-table, pe-avatar, pe-icon):not(:defined))) .portal-loading { display: none; }

/* ASP.NET unobtrusive validation toggles `input-validation-error` on an invalid
   field (both on the server render and live on the client); redden its border so
   a decorated pe-input field shows the failure. Loaded after the design-system
   CSS, so it beats the token `border-border` utility. */
.input-validation-error {
  border-color: var(--color-negative) !important;
}

/* Register / reset password-rule checklist. shared-utilities-global.js toggles
   .invalid/.valid on the five #pass-* items as rules are met. */
#password-contain {
  background: var(--color-surface-muted);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-control, .3rem);
  padding: .75rem 1rem;
}
#password-contain .invalid { color: var(--color-on-surface-muted); }
#password-contain .valid { color: var(--color-positive); }
#password-contain .valid::before { content: "\2713\00a0"; }

/* Support tickets — message bubbles + EasyMDE dark theme. Faithful port of the
   old FrontEnd/src/scss/support-tickets.scss (Vixon CSS is gone), used by
   ub-ticket-thread and ub-markdown-editor. Plain selectors (the components' /
   EasyMDE's / CodeMirror's own class names), not Tailwind utilities. Keeps the
   old rgba white overlays + syntax colours; only the --bs-* vars are swapped. */

/* Message timeline (ub-ticket-thread) */
.support-ticket-message {
  border-radius: var(--radius-panel, .5rem);
  padding: .875rem 1rem;
  border: 1px solid var(--color-border);
}
.support-ticket-message:not(:last-of-type) { margin-bottom: 1rem; }
.support-ticket-message.message-staff {
  background-color: color-mix(in srgb, var(--color-primary) 12%, transparent);
  border-left: 3px solid var(--color-primary);
  margin-left: 2rem;
}
.support-ticket-message.message-member {
  background-color: color-mix(in srgb, var(--color-on-surface-muted) 10%, transparent);
  border-left: 3px solid var(--color-on-surface-muted);
}
.support-ticket-message.message-system {
  background-color: transparent;
  border: 1px dashed color-mix(in srgb, var(--color-info) 35%, transparent);
  font-size: .85rem;
  color: var(--color-on-surface-muted);
}
.support-ticket-message-header { margin-bottom: .5rem; display: flex; flex-wrap: wrap; align-items: baseline; }
.support-ticket-message-body { line-height: 1.5; word-wrap: break-word; }
.support-ticket-message-body p:last-child { margin-bottom: 0; }
.support-ticket-message-body img { max-width: 100%; height: auto; }
.support-ticket-message-body pre, .support-ticket-message-body code { white-space: pre-wrap; word-wrap: break-word; }
.message-attachments {
  display: flex; flex-wrap: wrap; gap: 1rem; margin-top: .75rem; padding-top: .75rem;
  border-top: 1px solid var(--color-border);
}
@media (max-width: 576px) {
  .support-ticket-message.message-staff { margin-left: 0; }
  .support-ticket-message-header { flex-direction: column; gap: .125rem; }
}

/* EasyMDE dark theme (ub-markdown-editor) */
.EasyMDEContainer .editor-toolbar {
  background-color: rgba(255, 255, 255, 0.08);
  border: 1px solid var(--color-border) !important;
  border-bottom: 0 !important;
  border-top-left-radius: var(--radius-control, .3rem) !important;
  border-top-right-radius: var(--radius-control, .3rem) !important;
  opacity: 1;
}
.EasyMDEContainer .editor-toolbar button { color: rgba(255, 255, 255, 0.85) !important; }
.EasyMDEContainer .editor-toolbar button:hover,
.EasyMDEContainer .editor-toolbar button.active {
  background-color: rgba(255, 255, 255, 0.1);
  border-color: rgba(255, 255, 255, 0.2);
  color: #fff !important;
}
.EasyMDEContainer .editor-toolbar i.separator {
  border-left: 1px solid rgba(255, 255, 255, 0.15);
  border-right: 1px solid rgba(255, 255, 255, 0.02);
}
.EasyMDEContainer .CodeMirror {
  background-color: rgba(255, 255, 255, 0.03);
  color: #e6e6e6;
  border: 1px solid var(--color-border) !important;
  border-bottom-left-radius: var(--radius-control, .3rem) !important;
  border-bottom-right-radius: var(--radius-control, .3rem) !important;
}
.EasyMDEContainer .CodeMirror .CodeMirror-cursor { border-left-color: #fff; }
.EasyMDEContainer .CodeMirror .CodeMirror-selected { background: rgba(199, 234, 70, 0.25) !important; }
.EasyMDEContainer .CodeMirror .cm-header { color: #c7ea46; }
.EasyMDEContainer .CodeMirror .cm-strong { color: #fff; }
.EasyMDEContainer .CodeMirror .cm-em { color: #e6e6e6; font-style: italic; }
.EasyMDEContainer .CodeMirror .cm-link,
.EasyMDEContainer .CodeMirror .cm-url { color: #8fd0ff; }
.EasyMDEContainer .CodeMirror .cm-quote { color: #adb5bd; }
.EasyMDEContainer .CodeMirror .cm-comment { color: #c7ea46; }
.EasyMDEContainer .CodeMirror .cm-formatting { color: rgba(255, 255, 255, 0.45); }
.EasyMDEContainer .editor-preview,
.EasyMDEContainer .editor-preview-side {
  background-color: #1a1a2e;
  color: #e6e6e6;
  border-color: rgba(255, 255, 255, 0.12);
}
.EasyMDEContainer .editor-preview h1, .EasyMDEContainer .editor-preview h2,
.EasyMDEContainer .editor-preview h3, .EasyMDEContainer .editor-preview h4,
.EasyMDEContainer .editor-preview h5, .EasyMDEContainer .editor-preview h6 { color: #fff; }
.EasyMDEContainer .editor-preview a, .EasyMDEContainer .editor-preview-side a { color: #8fd0ff; }
.EasyMDEContainer .editor-preview pre, .EasyMDEContainer .editor-preview code { background: rgba(255, 255, 255, 0.08); }
.EasyMDEContainer .editor-preview blockquote { border-left: 3px solid rgba(199, 234, 70, 0.5); color: #adb5bd; }
.EasyMDEContainer .editor-statusbar { color: rgba(255, 255, 255, 0.55); }

/* Invalid state — redden the whole EasyMDE box (toolbar + editor), matching the
   red border the input fields get from .input-validation-error. The controller
   toggles this class on the ub-markdown-editor host. */
ub-markdown-editor.input-validation-error .editor-toolbar,
ub-markdown-editor.input-validation-error .CodeMirror {
  border-color: var(--color-negative) !important;
}

/* CTA link for CMS / rich-text (RTE) content, styled like a soft pe-button. The
   RTE can't hold a <pe-button> custom element, so authors put these classes on
   an <a>. Tailwind never scans CMS content, so this is plain token-driven CSS. */
.pe-cta {
  display: inline-flex;
  align-items: center;
  gap: 0.375rem;
  padding: 0.375rem 0.75rem;
  border: 1px solid var(--color-border);
  border-radius: var(--radius-control, 0.3rem);
  font-size: 0.8125rem;
  font-weight: 500;
  line-height: 1.25rem;
  color: var(--color-on-surface);
  text-decoration: none;
  transition: background-color 0.15s, border-color 0.15s, color 0.15s;
}
.pe-cta:hover { background-color: var(--color-surface-muted); }
.pe-cta-warning {
  border-color: color-mix(in srgb, var(--color-warning) 30%, transparent);
  background-color: color-mix(in srgb, var(--color-warning) 10%, transparent);
  color: var(--color-warning);
}
.pe-cta-warning:hover { background-color: color-mix(in srgb, var(--color-warning) 20%, transparent); }

/* Cookie-consent re-open launcher (ub-cookie-consent). The ub-* components share
   Portal Engine's prebuilt utility layer, which only carries the classes PE itself
   uses — so the launcher's own positioning/sizing utilities (bottom-4, right-4,
   size-11, z-[9998]) are never emitted and the button collapsed into the top-left
   corner. Like .pe-cta above, style it with plain token-driven CSS. Anchored to the
   bottom-left, slightly inset from the corner. */
.ub-cookie-launcher {
  position: fixed;
  left: 1.25rem;
  bottom: 1.25rem;
  z-index: 9998;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 2.75rem;
  height: 2.75rem;
  border-radius: 9999px;
  border: 1px solid var(--color-border);
  background-color: var(--color-surface-raised);
  color: var(--color-on-surface);
  box-shadow: var(--shadow-panel, 0 10px 25px rgb(0 0 0 / 0.25));
  cursor: pointer;
  transition: background-color 0.15s ease;
}
.ub-cookie-launcher:hover { background-color: var(--color-surface-muted); }

/* Cookie-consent banner + preferences overlay (ub-cookie-consent). Their z-index
   lives here for the same reason as the launcher above: the Tailwind z-[9999]
   utility is not in Portal Engine's prebuilt layer, so the fixed layer would fall
   to z-index:auto and sit beneath page panels whose opacity/transform forms a
   higher stacking context. Kept above .ub-cookie-launcher (9998) so the banner
   wins when both could paint. */
.ub-cookie-banner,
.ub-cookie-dialog {
  z-index: 9999;
}
