/* ============================================================================
   Systshare - SYSTAG light theme: the component layer.
   ----------------------------------------------------------------------------
   Everything here is either (a) a Bootstrap component that has no variable for
   the property we need, or (b) one of this app's own classes. Colours come from
   theme.css - no literals below except where a value is genuinely one-off.

   Nothing in this file uses `!important`. Bootstrap's component variants are
   themselves only custom-property assignments, so equal specificity plus later
   source order is enough to win.
   ========================================================================== */

/* ── Page frame ──────────────────────────────────────────────────────────── */

/* The body is a flex column (theme.css); main absorbs the leftover height so
   the footer sits on the viewport floor on short pages. `flex: 1 0 auto`
   rather than `flex: 1` - the auto basis keeps tall content from being
   compressed to fit. The header, hero and footer must not stretch or shrink. */
.sys-main { flex: 1 0 auto; }

.sys-header,
.sys-hero,
.sys-footer { flex: none; }

/* ── Base type ───────────────────────────────────────────────────────────── */

.sys-main > .container {
  padding-top: 40px;
  padding-bottom: 56px;
}

/* Page title. Rendered once, by the layout's hero band. */
.sys-title {
  margin: 0;
  max-width: 820px;
  font-size: 40px;
  font-weight: 700;
  line-height: 1.15;
  letter-spacing: var(--sys-ls-tight);
  text-transform: uppercase;
  color: var(--sys-brand-text);
  text-wrap: pretty;
  /* File names now render as the page title, and they can be long and
     unbroken - FileConfig and FileDownload both put one here. */
  overflow-wrap: anywhere;
}

@media (max-width: 767.98px) {
  .sys-title { font-size: 28px; }
}

/* Standfirst / intro paragraph. Replaces the `lead fs-6 text-center` idiom. */
.sys-lede {
  max-width: 720px;
  margin: 0 0 16px;
  font-size: 17px;
  line-height: 1.7;
  color: var(--sys-text);
}

.sys-lede:last-child { margin-bottom: 0; }

/* Section heading inside a panel, plus its rule.

   The app writes `<hr/><h2>Title</h2><hr/>` in a dozen places. Rather than
   hunt every instance, the heading grows its own rule and the neighbouring
   <hr>s are hidden - so that idiom renders correctly with no markup change. */
.sys-main h2,
.sys-main h3,
.sys-section-title {
  margin: 32px 0 22px;
  padding-bottom: 10px;
  font-size: 15px;
  font-weight: 600;
  letter-spacing: var(--sys-ls-wide);
  text-transform: uppercase;
  color: var(--sys-text);
  border-bottom: 1px solid var(--sys-hairline);
}

.sys-main h2:first-child,
.sys-main h3:first-child { margin-top: 0; }

.sys-main hr {
  margin: 28px 0;
  border: 0;
  border-top: 1px solid var(--sys-hairline);
  opacity: 1;
}

/* A hidden <hr> contributes no box, so the heading keeps its own margin -
   do not zero it here or the sections run together. */
.sys-main h2 + hr,
.sys-main h3 + hr,
.sys-main hr:has(+ h2),
.sys-main hr:has(+ h3) { display: none; }

/* ── Panel ───────────────────────────────────────────────────────────────── */

/* The one container in the system. Replaces `.bg-background` and the four
   ad-hoc spacing recipes that used to accompany it. */
.sys-panel {
  padding: 28px;
  background: var(--sys-surface);
  border: 1px solid var(--sys-border);
  border-radius: var(--sys-radius);
}

.sys-panel + .sys-panel { margin-top: 32px; }

@media (max-width: 575.98px) {
  .sys-panel { padding: 18px 14px; }
}

/* Two-panel grid on the upload screen. */
/* A .row's negative margin is half its gutter, and .container's padding is
   half the *default* gutter - so widening the gutter unconditionally makes the
   row hang 4px past the viewport. The wider gutter is only wanted where the
   columns actually sit side by side. */
.sys-grid { row-gap: 32px; }

@media (min-width: 992px) {
  .sys-grid { --bs-gutter-x: 32px; }
}

/* Columns stretch, so let the panels inside fill them - two panels of
   different content lengths still line up top and bottom. */
.sys-grid > [class*="col-"] > .sys-panel { height: 100%; }

/* ── Header and wordmark ─────────────────────────────────────────────────── */

.sys-header {
  background: var(--sys-surface);
  border-bottom: 1px solid var(--sys-border);
}

.sys-header .container-fluid {
  min-height: 82px;
  gap: 24px;
}

.sys-brand {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  padding: 0;
  text-decoration: none;
}

/* The asset carries a lot of empty canvas: 680x312 of which the artwork is
   only 636x97, so 69% of the height is transparent. A box sized to the
   artwork's own 6.56:1 ratio plus object-fit crops that padding away, which
   is why the height here is the height of the visible wordmark rather than
   of the file. Replace the numbers if the logo is ever re-exported tight.

   Both dimensions come off one custom property so that ratio survives every
   size: the wordmark is most of a phone's width at 28px, and the header only
   fits on one row there if it scales down. 5.2vw reaches the 28px ceiling at
   a 539px viewport, so from small up this renders exactly as it always did.
   The 18px floor only binds below ~346px, where the row has no width left to
   give: at 320px the parts come to 294 of the 304px available. */
.sys-brand-logo {
  --sys-brand-logo-h: clamp(18px, 5.2vw, 28px);
  height: var(--sys-brand-logo-h);
  width: calc(var(--sys-brand-logo-h) * 6.571);
  object-fit: cover;
  object-position: center;
  display: block;
  flex: none;
}

/* Text fallback, used only when the logo asset is missing. */
.sys-brand-mark,
.sys-brand-sep {
  font-size: 27px;
  font-weight: 700;
  line-height: 1;
}

.sys-brand-mark { letter-spacing: var(--sys-ls-brand); color: var(--sys-brand-text); }
.sys-brand-sep  { color: var(--sys-accent-text); }

/* Deployment label beside the wordmark - DEV, TEST and so on. Rendered only
   when AppSettings.EnvironmentName is set, so production shows the logo alone.
   Keeps the type of the app name it replaced, so the header reads unchanged. */
.sys-brand-env {
  font-size: 20px;
  font-weight: 400;
  padding-bottom: 5px;
  line-height: 1;
  letter-spacing: .02em;
  color: var(--sys-text);
  overflow-wrap: anywhere;
}

.sys-brand:hover .sys-brand-env { color: var(--sys-brand-text); }

/* Nav. The 2px accent underline is the only marker of the current page. */
.sys-header .navbar { padding-top: 0; padding-bottom: 0; }

.sys-header .nav-link {
  padding: 8px 0;
  font-size: 17px;
  color: var(--sys-text);
  border-bottom: var(--sys-rule-active) solid transparent;
}

.sys-header .nav-item + .nav-item { margin-left: 28px; }
.sys-header .nav-link:hover,
.sys-header .nav-link:focus { color: var(--sys-accent-text); }

.sys-header .nav-link.active {
  font-weight: 600;
  color: var(--sys-brand-text);
  border-bottom-color: var(--sys-accent);
}

.sys-header .navbar-toggler {
  border: 1px solid var(--sys-border);
  border-radius: var(--sys-radius);
  padding: 6px 10px;
}

/* The burger takes over below lg, not sm: expanded, the row needs about 850px
   (wordmark, label, four links, theme control), so a portrait tablet wrapped
   the label under the logo. */
@media (max-width: 991.98px) {
  .sys-header .container-fluid { min-height: 64px; }
  .sys-header .navbar-collapse { padding-bottom: 12px; }
  .sys-header .nav-item + .nav-item { margin-left: 0; }
  .sys-header .nav-link {
    padding: 8px 12px;
    border-bottom: 0;
    border-left: var(--sys-rule-active) solid transparent;
  }
  .sys-header .nav-link.active { border-left-color: var(--sys-accent); }
}

/* ── Theme switcher ─────────────────────────────────────────────────────── */

/* Three states rather than two, so "follow the system" stays reachable after
   the user has once chosen manually. It sits outside .navbar-collapse so it
   does not disappear into the burger menu on a phone. */
.sys-theme {
  display: inline-flex;
  margin-left: auto;
  margin-right: 12px;
  border: 1px solid var(--sys-border-btn);
  border-radius: var(--sys-radius);
  overflow: hidden;
}

.sys-theme button {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 34px;
  height: 30px;
  padding: 0;
  color: var(--sys-muted);
  background: var(--sys-surface);
  border: 0;
  cursor: pointer;
}

.sys-theme button + button { border-left: 1px solid var(--sys-border); }

.sys-theme button:hover { color: var(--sys-accent-text); }

.sys-theme button:focus-visible {
  outline: var(--bs-focus-ring-width) solid var(--bs-focus-ring-color);
  outline-offset: -2px;
}

/* The pressed state carries the same accent underline the nav uses, so the
   control reads as part of the header rather than as a stray widget. */
.sys-theme button[aria-pressed="true"] {
  color: var(--sys-brand-text);
  background: var(--sys-surface-tint);
  box-shadow: inset 0 calc(-1 * var(--sys-rule-active)) 0 0 var(--sys-accent);
}

.sys-theme svg {
  width: 16px;
  height: 16px;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.6;
  stroke-linecap: round;
  stroke-linejoin: round;
}

/* Wordmark, theme control and burger have to share one row on a phone: let the
   burger wrap and it lands alone under a mostly empty header, with the auto
   left margin below reading as a hole between the wordmark and the control.
   Fitting them is a width budget, met by trimming each part rather than any one
   of them - side padding, the gap, the wordmark, the label and both controls.
   At 360px that leaves 44px of slack, at 320px - the narrowest phone worth
   supporting - 10px. Check the arithmetic again before growing anything here.

   `flex-wrap` stays: the open menu is a flex-basis:100% item and still has to
   drop to its own row. That is also why the two gaps are set separately -
   the `gap` shorthand would take the row gap with it, and the 24px it used to
   inherit is what made this header 97px tall when the menu was open.

   The layout rules apply wherever the burger shows (below lg); the size trims
   only on a phone (below sm), where the width budget actually bites. */
@media (max-width: 991.98px) {
  .sys-header .container-fluid {
    flex-wrap: wrap;
    column-gap: 8px;
    row-gap: 2px;
  }

  /* The brand is what yields if the budget is ever blown - a long deployment
     name ellipsises and the two controls keep their size. The max-width is
     what does the work: flex wraps a line before it shrinks anything on it, so
     `min-width: 0` alone never fires - the burger just drops to a second row
     instead. Capping the brand bounds it while the line is still being filled.
     The subtracted width is the rest of the row: control + burger + the two
     8px gaps - 106 + 52 + 16 here, 86 + 43 + 16 on a phone below. Keep both in
     step if any of those change. */
  .sys-brand {
    min-width: 0;
    max-width: calc(100% - 174px);
    overflow: hidden;
  }

  .sys-theme { margin-right: 0; flex: none; }
  .sys-header .navbar-toggler { flex: none; }
}

@media (max-width: 575.98px) {
  .sys-header .container-fluid { --bs-gutter-x: 1rem; }

  .sys-brand { max-width: calc(100% - 145px); }

  .sys-brand-env {
    font-size: 14px;
    padding-bottom: 3px;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
  }

  .sys-theme button { width: 28px; }

  .sys-header .navbar-toggler { padding: 5px 8px; }
  .sys-header .navbar-toggler-icon { width: 1.25em; height: 1.25em; }
}

/* Below lg the DOM order is what puts the control on the same row as the
   burger while the open menu wraps beneath it, so it is left alone there. From
   lg up the menu no longer wraps and `order` is safe, which lets the control
   sit with the nav links instead of orphaned beside the wordmark. */
@media (min-width: 992px) {
  .sys-theme {
    order: 1;
    margin-left: 24px;
    margin-right: 0;
  }
}

/* ── Hero band ───────────────────────────────────────────────────────────── */

.sys-hero {
  padding: 56px 0 48px;
  background: var(--sys-surface-tint);
  border-bottom: 1px solid var(--sys-border);
}

.sys-hero .sys-title + * { margin-top: 16px; }

.sys-hero ul {
  max-width: 820px;
  margin: 16px 0 0;
  padding-left: 20px;
  color: var(--sys-text);
}

.sys-hero ul ul {
  margin-top: 8px;
  font-size: 15px;
  color: var(--sys-text);
}

.sys-hero li + li { margin-top: 6px; }

@media (max-width: 767.98px) {
  .sys-hero { padding: 32px 0 28px; }
}

/* ── Footer ──────────────────────────────────────────────────────────────── */

.sys-footer {
  padding: 22px 0;
  font-size: 14px;
  color: var(--sys-text);
  background: var(--sys-surface-tint);
  border-top: 1px solid var(--sys-border);
}

.sys-footer a { color: var(--sys-text); text-decoration: none; }
.sys-footer a:hover { color: var(--sys-accent-text); text-decoration: underline; }

/* ── Buttons ─────────────────────────────────────────────────────────────── */

.btn {
  --bs-btn-font-size: 16px;
  --bs-btn-font-weight: 600;
  --bs-btn-border-width: var(--sys-btn-border-w);
  --bs-btn-border-radius: var(--sys-radius);
  letter-spacing: var(--sys-ls-btn);
}

/* Primary action. The mockup's signature move was to hover accent red, but on a
   filled button that reads as a warning: the upload button and the delete
   button beside it announced the same colour, and red is the app's destructive
   signal everywhere else. Filled buttons now deepen within the brand instead.
   Red-on-hover is kept where it still means "link" - nav, footer, .btn-link. */
.btn-primary,
.btn-success,
.btn-info,
.btn-dark {
  --bs-btn-color: #fff;
  --bs-btn-bg: var(--sys-brand);
  --bs-btn-border-color: var(--sys-brand);
  --bs-btn-hover-color: #fff;
  --bs-btn-hover-bg: var(--sys-brand-hover);
  --bs-btn-hover-border-color: var(--sys-brand-hover);
  --bs-btn-active-color: #fff;
  --bs-btn-active-bg: var(--sys-brand-active);
  --bs-btn-active-border-color: var(--sys-brand-active);
  --bs-btn-disabled-color: #fff;
  --bs-btn-disabled-bg: var(--sys-faint);
  --bs-btn-disabled-border-color: var(--sys-faint);
  --bs-btn-padding-x: 28px;
  --bs-btn-padding-y: 12px;
}

/* Secondary / ghost. Also catches `btn-outline-info`, which the app uses for
   its copy-to-clipboard buttons. */
.btn-secondary,
.btn-light,
.btn-outline-primary,
.btn-outline-secondary,
.btn-outline-info,
.btn-outline-dark {
  --bs-btn-color: var(--sys-brand-text);
  --bs-btn-bg: var(--sys-surface);
  --bs-btn-border-color: var(--sys-border-btn);
  --bs-btn-hover-color: var(--sys-brand-text);
  --bs-btn-hover-bg: var(--sys-surface);
  --bs-btn-hover-border-color: var(--sys-brand-text);
  --bs-btn-active-color: var(--sys-brand-text);
  --bs-btn-active-bg: var(--sys-surface-tint);
  --bs-btn-active-border-color: var(--sys-brand-text);
  --bs-btn-disabled-color: var(--sys-faint);
  --bs-btn-disabled-bg: var(--sys-surface);
  --bs-btn-disabled-border-color: var(--sys-border);
  --bs-btn-padding-x: 22px;
  --bs-btn-padding-y: 12px;
}

/* Destructive rests one step darker than the accent, so that hovering a
   primary button never makes it look like the delete button beside it. */
.btn-danger,
.btn-warning {
  --bs-btn-color: #fff;
  --bs-btn-bg: var(--sys-accent-dark);
  --bs-btn-border-color: var(--sys-accent-dark);
  --bs-btn-hover-color: #fff;
  --bs-btn-hover-bg: var(--sys-danger-fill);
  --bs-btn-hover-border-color: var(--sys-danger-fill);
  --bs-btn-active-color: #fff;
  --bs-btn-active-bg: var(--sys-danger-fill);
  --bs-btn-active-border-color: var(--sys-danger-fill);
  --bs-btn-padding-x: 22px;
  --bs-btn-padding-y: 12px;
}

.btn-link {
  --bs-btn-color: var(--sys-brand-text);
  --bs-btn-hover-color: var(--sys-accent-text);
  --bs-btn-font-weight: 500;
}

.btn-sm {
  --bs-btn-font-size: 14px;
  --bs-btn-padding-x: 14px;
  --bs-btn-padding-y: 8px;
}

.btn-lg { --bs-btn-font-size: 17px; }

/* Icon-only buttons sitting in a data row need to stay compact. */
.data-row .btn,
.data-row-icon .btn {
  --bs-btn-padding-x: 12px;
  --bs-btn-padding-y: 8px;
  --bs-btn-font-size: 14px;
}

/* Centred action group. Replaces `d-flex justify-content-center gap-3`. */
.sys-actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: 16px;
  margin-top: 28px;
}

.sys-actions .vr {
  color: var(--sys-border);
  opacity: 1;
  align-self: stretch;
}

/* Responsive label/icon swap on the app-version tables (carried over). */
.ipabtn { display: none; }

/* ── Forms ───────────────────────────────────────────────────────────────── */

/* Bootstrap draws the select chevron in gray-700, which is off-palette. */
.form-select {
  --bs-form-select-bg-img: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3e%3cpath fill='none' stroke='%234c6a79' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='m2 5 6 6 6-6'/%3e%3c/svg%3e");
}

.form-control,
.form-select {
  padding: 11px 14px;
  color: var(--sys-brand-text);
  background-color: var(--sys-surface);
  border: 1px solid var(--sys-border-input);
  border-radius: var(--sys-radius);
}

/* A .form-select needs room on the right for its chevron. The padding
   shorthand above drops Bootstrap's 2.25rem, which left the arrow sitting on
   top of the value on any narrow select - the admin table's page-length
   control most visibly. */
.form-select { padding-right: 36px; }

/* Bootstrap's small variants, restated: the shared shorthand above outranks
   them on source order, which was rendering every "sm" control at full size. */
.form-control-sm {
  padding: 7px 10px;
  font-size: 14px;
}

.form-select-sm {
  padding: 7px 30px 7px 10px;
  font-size: 14px;
  background-position: right 8px center;
  background-size: 13px 10px;
}

.form-control::placeholder { color: var(--sys-muted); }

.form-control:focus,
.form-select:focus {
  color: var(--sys-brand-text);
  border-color: var(--sys-brand-text);
  box-shadow: 0 0 0 2px rgba(var(--sys-brand-rgb), .18);
}

.form-control[type="file"] { padding: 9px 14px; }

.form-control::file-selector-button {
  padding: 9px 14px;
  margin: -9px 14px -9px -14px;
  color: var(--sys-brand-text);
  background: var(--sys-surface-tint);
  border: 0;
  border-right: 1px solid var(--sys-border-input);
  font-weight: 500;
}

.form-label {
  margin-bottom: 6px;
  font-size: 13px;
  font-weight: 600;
  letter-spacing: var(--sys-ls-wide);
  text-transform: uppercase;
  color: var(--sys-text);
}

.form-text { color: var(--sys-text); font-size: 13px; }

.form-check-input:checked {
  background-color: var(--sys-brand);
  border-color: var(--sys-brand);
}

.form-floating > label { color: var(--sys-text); }

/* Addon used as a field label - the app's own idiom. The min-width keeps the
   labels down a form aligned with each other. */
.input-group-text {
  min-width: 112px;
  justify-content: flex-start;
  font-weight: 500;
  color: var(--sys-brand-text);
  background-color: var(--sys-surface-tint);
  border: 1px solid var(--sys-border-input);
  border-radius: var(--sys-radius);
}

/* An addon holding only an icon is not a label and must not be padded out to
   label width - the captcha's lock is the one case. */
.input-group-text:has(> [class*="bi-"]) {
  min-width: 0;
  justify-content: center;
}

/* Several pages put `label.input-group-text` *outside* an `.input-group`,
   where Bootstrap gives it no layout at all. Rather than rewrite the ~30
   scaffolded Identity pages, make it read as a deliberate stacked label chip. */
:not(.input-group) > label.input-group-text {
  display: block;
  width: 100%;
  border-bottom: 0;
  border-radius: var(--sys-radius) var(--sys-radius) 0 0;
}

:not(.input-group) > label.input-group-text + .form-control,
:not(.input-group) > label.input-group-text + .form-select,
:not(.input-group) > label.input-group-text + textarea {
  border-radius: 0 0 var(--sys-radius) var(--sys-radius);
}

/* Password generator row (carried over: #passwd-gen-contianer - the typo is
   in the markup too, so the selector has to keep it). */
#passwd-gen-contianer {
  display: flex;
  flex-direction: column;
  gap: 10px;
  margin-bottom: 18px;
}

/* Validation */
.text-danger { color: var(--sys-danger-text); }
.validation-summary-errors { margin: 0; padding-left: 20px; font-size: 14px; }
.field-validation-error { display: inline-block; font-size: 13px; }

/* ── Fieldset ────────────────────────────────────────────────────────────── */

.sys-fieldset {
  margin-top: 28px;
  padding: 18px 20px 20px;
  border: 1px solid var(--sys-border);
  border-radius: var(--sys-radius);
}

/* A <legend> is laid out in the fieldset's top border, interrupting it - but
   only while it stays short. Give it horizontal padding for the gap and no
   vertical padding, or the browser pushes the whole border box down below it
   and the rule ends up under the label instead of through it. */
.sys-fieldset > legend {
  float: none;
  width: auto;
  margin: 0;
  padding: 0 10px 0 0;
  font-size: 15px;
  font-weight: 600;
  line-height: 1.2;
  letter-spacing: var(--sys-ls-wide);
  text-transform: uppercase;
  color: var(--sys-text);
}

.sys-fieldset > legend + * { margin-top: 10px; }

.sys-main h2 + .sys-fieldset,
.sys-main h3 + .sys-fieldset { margin-top: 0; }

/* The deletion-schedule group is the one place the design puts a red box, with
   the label as a solid chip straddling the top border. */
.sys-fieldset--accent { border: var(--sys-rule-active) solid var(--sys-accent); }

.sys-fieldset--accent > legend {
  padding: 0 10px 0 0;
  text-transform: none;
  letter-spacing: 0;
}

.sys-legend-chip {
  display: inline-block;
  padding: 5px 12px;
  font-size: 13px;
  font-weight: 600;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: #fff;
  background-color: var(--sys-accent);
}

.sys-fieldset-note {
  margin: 12px 0 0;
  font-size: 13px;
  line-height: 1.55;
  color: var(--sys-text);
}

/* ── Dropzone ────────────────────────────────────────────────────────────── */

#dropzone {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 10px;
  width: 100%;
  height: auto;
  padding: 38px 20px;
  text-align: center;
  background-color: var(--sys-surface-sunken);
  border: 2px dashed var(--sys-border-dashed);
  border-radius: var(--sys-radius);
}

#dropzone svg {
  width: 44px;
  height: 44px;
  margin: 0;
  color: var(--sys-brand-text);
}

#dropzone br { display: none; }

#dropzone p {
  margin: 0;
  font-size: 18px;
  font-weight: 600;
  color: var(--sys-brand-text);
}

.sys-dropzone-hint {
  margin: 0;
  font-size: 14px;
  color: var(--sys-text);
}

/* ── Progress ────────────────────────────────────────────────────────────── */

/* site.js writes the percentage into the bar's own innerHTML, so the bar has
   to stay tall enough to hold that text. */
.progress {
  height: 22px;
  font-size: 13px;
  background-color: var(--sys-track);
  border-radius: var(--sys-radius-pill);
  overflow: hidden;
}

.progress-bar {
  font-weight: 600;
  letter-spacing: var(--sys-ls-btn);
  color: #fff;
  background-color: var(--sys-brand);
  background-image: repeating-linear-gradient(135deg,
      var(--sys-brand) 0 10px, var(--sys-brand-2) 10px 20px);
  background-size: 40px 40px;
  border-radius: var(--sys-radius-pill);
  animation: sys-barmove 1s linear infinite;
}

@keyframes sys-barmove {
  to { background-position: 40px 0; }
}

@media (prefers-reduced-motion: reduce) {
  .progress-bar { animation: none; }
}

.spinner-border { color: var(--sys-brand-text); }

/* ── Key/value rows ──────────────────────────────────────────────────────── */

/* Carried over verbatim from the old stylesheet - these are the app's own and
   are what keeps long hashes and URLs from blowing out the grid. */
.data-row {
  word-break: break-word;
  display: flex;
  justify-content: space-between;
  align-items: center;
}

.data-row-icon {
  word-break: break-word;
  display: flex;
  align-items: center;
}

/* The label and its value are siblings inside one `.row`, so a border-bottom
   on each cell lines up into a single rule across the pair - and the container
   supplies the line above the first. Works stacked on mobile too. */
.row:has(> .data-row) {
  --bs-gutter-x: 0;
  border-top: 1px solid var(--sys-hairline);
}

.row > .data-row,
.row > .data-row-icon {
  min-height: 46px;
  padding: 11px 0;
  font-weight: 500;
  color: var(--sys-brand-text);
  border-bottom: 1px solid var(--sys-hairline);
}

.row > .data-row > b {
  font-weight: 500;
  color: var(--sys-text);
}

.sys-mono {
  font-family: var(--bs-font-monospace);
  font-size: .95em;
  word-break: break-all;
  color: var(--sys-brand-text);
}

/* The glyph carries its size as a height="150" attribute, and Bootstrap's reset
   puts everything in border-box - so padding alone would be subtracted from
   those 150px and shrink the artwork to 130 rather than open space beneath it.
   content-box keeps the icon at its intended size and adds the 20px below. */
.sys-app-glyph {
  color: var(--sys-brand-text);
  box-sizing: content-box;
  padding-bottom: 20px;
}

.sys-qr {
  width: 160px;
  height: 160px;
}

/* ── Media players ───────────────────────────────────────────────────────── */

/* Inline video player. Sized like an image rather than with a fixed width: leaving both
   dimensions auto and giving only maxima lets the element keep the clip's own aspect
   ratio while fitting inside both bounds, so nothing is letterboxed - a `width: 100%`
   here would pillarbox every landscape clip the moment max-height bit. The height cap
   keeps a portrait clip from filling the screen. The matte shows only while metadata is
   still loading and is black in either theme, which is why this one colour is a literal. */
.sys-video {
  display: block;
  max-width: 100%;
  max-height: 70vh;
  margin: 20px auto 0;
  background: #000;
  border-radius: var(--sys-radius);
}

/* Inline audio player. The native control bar carries its own intrinsic height, so only
   the width needs constraining - no matte or radius either, because the control bar is
   drawn by the browser and paints over both. It already follows the theme: Bootstrap
   sets `color-scheme: dark` on [data-bs-theme=dark], which is what native media
   controls key off. */
.sys-audio {
  display: block;
  width: 100%;
  margin: 20px auto 0;
}

/* ── Alerts ──────────────────────────────────────────────────────────────── */

.alert {
  padding: 14px 18px;
  font-size: 15px;
  border: 1px solid var(--sys-border);
  border-radius: var(--sys-radius);
}

.alert-success,
.alert-info,
.alert-primary,
.alert-secondary,
.alert-light {
  --bs-alert-color: var(--sys-brand-text);
  --bs-alert-bg: var(--sys-surface-tint);
  --bs-alert-border-color: var(--sys-border);
}

.alert-danger,
.alert-warning {
  --bs-alert-color: var(--sys-danger-text);
  --bs-alert-bg: var(--sys-danger-bg);
  --bs-alert-border-color: var(--sys-danger-border);
}

/* ── Modals ──────────────────────────────────────────────────────────────── */

.modal-content {
  border: 1px solid var(--sys-border);
  border-radius: var(--sys-radius);
  box-shadow: var(--sys-shadow);
}

.modal-header,
.modal-footer {
  padding: 18px 22px;
  border-color: var(--sys-hairline);
}

.modal-body { padding: 22px; }

.modal-title {
  font-size: 15px;
  font-weight: 600;
  letter-spacing: var(--sys-ls-wide);
  text-transform: uppercase;
  color: var(--sys-text);
}

.modal-body .modal-title {
  font-size: 17px;
  letter-spacing: 0;
  text-transform: none;
  color: var(--sys-brand-text);
}

.btn-close { --bs-btn-close-opacity: .5; }

/* ── Tabs and pills ─────────────────────────────────────────────────────── */

.nav-tabs {
  gap: 4px;
  border-bottom: 1px solid var(--sys-border);
}

.nav-tabs .nav-link {
  padding: 12px 18px;
  font-size: 15px;
  font-weight: 600;
  letter-spacing: var(--sys-ls-wide);
  text-transform: uppercase;
  color: var(--sys-text);
  background: transparent;
  border: 0;
  border-bottom: var(--sys-rule-active) solid transparent;
  border-radius: 0;
}

.nav-tabs .nav-link:hover,
.nav-tabs .nav-link:focus {
  isolation: auto;
  color: var(--sys-brand-text);
  border-bottom-color: var(--sys-border);
}

.nav-tabs .nav-link.active {
  color: var(--sys-brand-text);
  background: transparent;
  border-bottom-color: var(--sys-accent);
}

.tab-content > .tab-pane { padding-top: 24px; }

/* Vertical pills - the account area's side nav, which is the only nav in the
   app that already tracks its own active state. */
.sys-sidenav .nav-link {
  padding: 10px 14px;
  color: var(--sys-text);
  border-left: var(--sys-rule-active) solid transparent;
  border-radius: var(--sys-radius);
}

.sys-sidenav .nav-link:hover {
  color: var(--sys-brand-text);
  background: var(--sys-surface-tint);
}

.nav-pills .nav-link.active,
.nav-pills .show > .nav-link {
  font-weight: 600;
  color: var(--sys-brand-text);
  background: var(--sys-surface-tint);
}

.sys-sidenav .nav-link.active { border-left-color: var(--sys-accent); }

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

.table {
  --bs-table-color: var(--sys-text);
  --bs-table-bg: transparent;
  --bs-table-border-color: var(--sys-hairline);
  --bs-table-striped-bg: var(--sys-surface-sunken);
  --bs-table-striped-color: var(--sys-text);
  --bs-table-hover-bg: var(--sys-surface-tint);
  --bs-table-hover-color: var(--sys-brand-text);
  margin-bottom: 0;
}

.table > thead th {
  padding: 12px 10px;
  font-size: 13px;
  font-weight: 600;
  letter-spacing: .1em;
  text-transform: uppercase;
  white-space: nowrap;
  color: var(--sys-text);
  border-bottom: 1px solid var(--sys-border);
}

.table > tbody td {
  padding: 12px 10px;
  vertical-align: middle;
  border-color: var(--sys-hairline);
}

.table caption {
  caption-side: top;
  padding: 0 0 10px;
  font-size: 13px;
  color: var(--sys-text);
}

/* App-version list becomes a scroll box on small screens (carried over). */
@media screen and (max-width: 600px) {
  .ipaversiontable {
    display: block;
    height: 300px;
    overflow-y: scroll;
  }

  .pcbtn { display: none; }
  .ipabtn { display: block; }
}

/* ── DataTables 2.x chrome ───────────────────────────────────────────────── */

/* The admin tables generate their toolbar, search box, info line and pager in
   JavaScript, so this is the only way to reach them. */
.dt-container { font-size: 15px; }

.dt-container .dt-layout-row {
  align-items: center;
  margin: 0 0 14px;
}

.dt-container .dt-length label,
.dt-container .dt-search label {
  margin: 0 8px 0 0;
  font-size: 13px;
  font-weight: 600;
  letter-spacing: var(--sys-ls-wide);
  text-transform: uppercase;
  color: var(--sys-text);
}


.dt-container .dt-info {
  padding-top: 12px;
  font-size: 13px;
  color: var(--sys-text);
}

.dt-container .dt-empty { color: var(--sys-text); }

.dt-container .dt-paging .page-link {
  color: var(--sys-brand-text);
  border-color: var(--sys-border);
  border-radius: var(--sys-radius);
}

.dt-container .dt-paging .page-link:hover {
  color: var(--sys-accent-text);
  background: var(--sys-surface-tint);
}

.dt-container .dt-paging .page-item.active .page-link {
  color: #fff;
  background: var(--sys-brand);
  border-color: var(--sys-brand);
}

.dt-container .dt-paging .page-item.disabled .page-link { color: var(--sys-faint); }

/* DataTables writes an explicit pixel width onto the table, and the admin
   file list has eight columns of German headers - on a phone that is 1070px
   wide. Let its own wrapper scroll instead of the whole page. */
.dt-container .col-12:has(> table.dataTable) {
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
}

table.dataTable thead > tr > th.dt-orderable-asc,
table.dataTable thead > tr > th.dt-orderable-desc { cursor: pointer; }

table.dataTable thead > tr > th span.dt-column-order::before,
table.dataTable thead > tr > th span.dt-column-order::after {
  color: var(--sys-faint);
  opacity: 1;
}

table.dataTable thead > tr > th.dt-ordering-asc span.dt-column-order::before,
table.dataTable thead > tr > th.dt-ordering-desc span.dt-column-order::after {
  color: var(--sys-accent-text);
}

/* ── Captcha ─────────────────────────────────────────────────────────────── */

/* Was captcha-code-design.css, which also shipped a global `.input-group-text`
   override painting every addon in the app dark grey. Only these belong. */
#SchutzInputText {
  color: var(--sys-brand-text);
  background-color: var(--sys-surface);
}

#SchutzInputText::placeholder { color: var(--sys-muted); }

.refresh-button {
  padding: 10px;
  color: var(--sys-brand-text);
}
