/*
   CSS styling examples for the Vaadin app.

   Visit https://vaadin.com/docs/styling/application-theme/ for more information.
*/

@import "./branding/branding.css";

/* The official Inter build (rsms.me), not the npm @fontsource one: fontsource's
   subsetting drops `zero`, `cv05` and `cv08`, which are why Inter was chosen.
   OFL-1.1; the licence travels with the file in fonts/. */
@font-face {
  font-family:  InterVariable;
  font-style:   normal;
  font-weight:  100 900;
  font-display: swap;
  src: url('./fonts/InterVariable.woff2') format('woff2');
}

.bool-true  { color: var(--lumo-success-color); }
.bool-false { color: var(--lumo-error-color);   }

html {
  /* One font on every PC; the system stack is only the fallback. */
  --lumo-font-family: InterVariable, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;

  /* Codes: slashed zero, serifed I, tailed l, so 0/O and I/l/1 differ in Item
     and Work Order numbers. Quantities opt back out below. */
  font-variant-numeric:  slashed-zero;
  font-feature-settings: "cv05", "cv08";

  /* A read-only value is what the user came to read: plain weight, and (below)
     body colour. Labels stay medium and grey. */
  --vaadin-input-field-value-font-weight: 400;
  --vaadin-input-field-label-font-weight: 500;

  /* .s-modal__header mixes the instance tint into this. */
  --s-surface: var(--lumo-base-color);

  /* Four working sizes: 12 labels, headers and badges; 14 body and grids;
     16 panel titles; 20 page titles. */
  --lumo-font-size: 1rem;
  --lumo-font-size-xxxl: 1.75rem;
  --lumo-font-size-xxl: 1.375rem;
  --lumo-font-size-xl: 1.25rem;
  --lumo-font-size-l: 1rem;
  --lumo-font-size-m: 0.875rem;
  --lumo-font-size-s: 0.75rem;
  --lumo-font-size-xs: 0.75rem;
  --lumo-font-size-xxs: 0.75rem;
  --lumo-line-height-m: 1.4;
  --lumo-line-height-s: 1.2;
  --lumo-line-height-xs: 1.1;
  --lumo-size-xl: 2.5rem;
  --lumo-size-l: 2rem;
  --lumo-size-m: 1.75rem;
  --lumo-size-s: 1.5rem;
  --lumo-size-xs: 1.25rem;
  --lumo-space-xl: 1.75rem;
  --lumo-space-l: 1.125rem;
  --lumo-space-m: 0.5rem;
  --lumo-space-s: 0.25rem;
  --lumo-space-xs: 0.125rem;
}

vaadin-text-field::part(label),
vaadin-text-area::part(label),
vaadin-combo-box::part(label),
vaadin-date-picker::part(label),
vaadin-number-field::part(label),
vaadin-integer-field::part(label),
vaadin-select::part(label) {
    padding-top: 2px;
    padding-bottom: 2px;
    padding-right: 2px;
}

vaadin-text-field,
vaadin-password-field,
vaadin-text-area,
vaadin-combo-box,
vaadin-date-picker,
vaadin-number-field,
vaadin-integer-field,
vaadin-select {
    padding-top: 4px;
}

/* Lumo's vaadin-input-container greys a read-only value to its label's colour. */
:is(vaadin-text-field, vaadin-text-area, vaadin-combo-box, vaadin-date-picker,
    vaadin-number-field, vaadin-integer-field, vaadin-select, vaadin-password-field)[readonly]::part(input-field) {
  color: var(--lumo-body-text-color);
}

/* A quantity has no O to confuse with 0, so it keeps plain zeros. */
vaadin-number-field,
vaadin-integer-field {
  font-variant-numeric: tabular-nums;
}

/* ---------------------------------------------------------------------------
   Spinner step buttons must not make the field taller than a plain one.

   Lumo sizes a step button 1.5em against its own font-size of --lumo-icon-size-m
   (itself 1.5em of the field's font). At this theme's --lumo-font-size-m of
   0.875rem that is a 31.5px button inside a field whose --lumo-size-m is 28px,
   so SIntegerEdit.withSpin() stands 3.5px taller than SLineEdit beside it.
   Pinning the button box to the field height removes the overflow; the icon
   itself keeps its own font-size and stays centred.

   MEASURED: input-field height goes 31.50px -> 28.00px, matching vaadin-text-field.
   --------------------------------------------------------------------------- */
vaadin-integer-field::part(decrease-button),
vaadin-integer-field::part(increase-button),
vaadin-number-field::part(decrease-button),
vaadin-number-field::part(increase-button) {
    height: var(--lumo-size-m);
}

vaadin-horizontal-layout.red {
  background-color: red;
}

/* ---------------------------------------------------------------------------
   Baseline-row correction  (applied by SHorz.setAlignItems / addClassName)

   Vaadin 24/25 fields no longer export a usable text baseline. A field WITH a
   label, a field WITHOUT one, and a Span/Checkbox each hand the flex container
   a different reference line, so align-items: baseline lines up three
   unrelated things. Lumo used to paper over this with a line-height rule and
   align-self: baseline on the field host; both were removed upstream because
   they broke align-items: stretch and distorted non-field-height components.

   These rules push the odd ones out back onto the line used by a labelled
   field's input text. They engage only in rows that actually contain a
   labelled field -- a row of bare fields is already self-consistent.

   MEASURED, NOT DERIVED: the two offsets were obtained by rendering these
   components in headless Chromium against this theme and reading back the
   text positions. They are not a clean multiple of the font size (the ratio
   moves from .32em to .51em across a 0.75x-1.5x scale sweep), so they are
   valid for the current font (InterVariable), --lumo-font-size-m (0.875rem),
   --lumo-font-size-s (0.75rem, the label) and --lumo-size-m (1.75rem) only.
   Change any of them and these need re-measuring. The move to Inter and 12px
   labels shifted them from -5.75px / -4.95px; the new values reproduce the
   old alignment to the hundredth of a pixel.
   --------------------------------------------------------------------------- */

/* Matches either the class SHorz.setAlignItems adds, or the inline style Flow
   writes for setAlignItems(BASELINE) directly -- so the correction does not
   depend on the row having been tagged from Java. */

:is(.s-baseline-row,
    [style*="align-items: baseline"]:not(vaadin-vertical-layout),
    [style*="align-items:baseline"]:not(vaadin-vertical-layout)):has(:is(vaadin-text-field,
                                             vaadin-combo-box,
                                             vaadin-date-picker,
                                             vaadin-number-field,
                                             vaadin-integer-field,
                                             vaadin-select,
                                             vaadin-password-field)[has-label]) {
  --s-baseline-shift-field: -5px;
  --s-baseline-shift-text:  -3.95px;
}

:is(.s-baseline-row,
    [style*="align-items: baseline"]:not(vaadin-vertical-layout),
    [style*="align-items:baseline"]:not(vaadin-vertical-layout)) > :is(vaadin-text-field,
                                           vaadin-combo-box,
                                           vaadin-date-picker,
                                           vaadin-number-field,
                                           vaadin-integer-field,
                                           vaadin-select,
                                           vaadin-password-field):not([has-label]) {
  position: relative;
  top: var(--s-baseline-shift-field, 0);
}

:is(.s-baseline-row,
    [style*="align-items: baseline"]:not(vaadin-vertical-layout),
    [style*="align-items:baseline"]:not(vaadin-vertical-layout)) > :is(span, label, vaadin-checkbox) {
  position: relative;
  top: var(--s-baseline-shift-text, 0);
}

label {
  white-space: nowrap;
  padding-bottom: 1px !important;
}

/* Opt-out of the nowrap above. Right for a field label sitting in a laid-out row, wrong for a
   checkbox standing alone in a dialog's message area, where the caption is a sentence and the
   dialog sizes itself to its own message text -- a caption longer than that (or a longer
   translation of a caption that fit in English) spills past the overlay edge instead of
   wrapping. Applied from Java via SCheckBox.withClassName("s-wrap-label"). */
vaadin-checkbox.s-wrap-label label {
  white-space: normal;
}

span {
  white-space: nowrap;
}

span.caption {
  text-indent: -5px;
  margin-bottom: -5px;
}

has-label {
  padding-top: 0;
}

vaadin-combo-box.leftpad {
  padding-left: 5px;
}

vaadin-checkbox.indent {
  padding-left: 5px;
}

vaadin-text-field.green {
  --vaadin-input-field-label-color: var(--s-status-good);
}

vaadin-text-field.yellow {
  --vaadin-input-field-label-color: var(--s-status-warn);
}

vaadin-text-field.red {
  --vaadin-input-field-label-color: var(--s-status-bad);
}

/* Side padding stays at 2px: SDataList.alignments gives most columns a fixed pixel
   width sized for it. At 8px every fixed column lost 12px, and dates, quantities
   and the constraint status were cut off. The extra room goes top and bottom. */
vaadin-selection-grid-cell-content {
  padding: 4px 2px;
}

/* 12px, the size the fixed column widths were set for (as 12px monospace); at 14px
   Inter a full PERCENT or INTEGER value no longer fits. Body font and tabular digits
   keep columns aligned, and a quantity keeps plain zeros. */
vaadin-selection-grid.styling::part(numeric) {
  font-family: inherit;
  font-size: var(--lumo-font-size-xs);
  font-variant-numeric: tabular-nums;
}

vaadin-selection-grid.styling::part(GREEN)      { color: var(--s-status-good);  }
vaadin-selection-grid.styling::part(BLUE)       { color: var(--s-status-info);  }
vaadin-selection-grid.styling::part(ORANGE)     { color: var(--s-status-warn);  }
vaadin-selection-grid.styling::part(RED)        { color: var(--s-status-bad);   }
vaadin-selection-grid.styling::part(WARN)       { color: var(--s-status-warn);  }
vaadin-selection-grid.styling::part(ALERT)      { color: var(--s-status-bad);   }
vaadin-selection-grid.styling::part(PREMATURE)  { color: var(--s-status-info);  }
vaadin-selection-grid.styling::part(INACTIVE)   { color: var(--s-status-muted); }
vaadin-selection-grid.styling::part(GREENZONE)  { color: var(--s-status-good);  }
vaadin-selection-grid.styling::part(YELLOWZONE) { color: var(--s-status-warn);  }
vaadin-selection-grid.styling::part(REDZONE)    { color: var(--s-status-bad);   }
vaadin-selection-grid.styling::part(EXCESS)     { color: var(--s-status-info);  }
vaadin-selection-grid.styling::part(VALID)      { color: var(--s-status-good);  }

/* Colour alone fails colour-blind users, so the buffer zones carry a shape too. */
vaadin-selection-grid.styling::part(GREENZONE),
vaadin-selection-grid.styling::part(YELLOWZONE),
vaadin-selection-grid.styling::part(REDZONE)            { font-weight: 500; }
vaadin-selection-grid.styling::part(GREENZONE)::before  { content: "●"; }
vaadin-selection-grid.styling::part(YELLOWZONE)::before { content: "▲"; }
vaadin-selection-grid.styling::part(REDZONE)::before    { content: "■"; }
vaadin-selection-grid.styling::part(GREENZONE)::before,
vaadin-selection-grid.styling::part(YELLOWZONE)::before,
vaadin-selection-grid.styling::part(REDZONE)::before {
  font-size:   0.7em;
  margin-left: 8px;
  align-self:  center;
}

:is(vaadin-grid, vaadin-selection-grid).styling {
  border-radius: 6px;
  --lumo-contrast-10pct: rgb(15 23 42 / 0.07);   /* softer column and row rules */
}

:is(vaadin-grid, vaadin-selection-grid).styling::part(header-cell) {
  background-color: color-mix(in srgb, var(--lumo-contrast) 3%, var(--lumo-base-color));
  font-weight:      600;
  color:            var(--lumo-secondary-text-color);
}

/* Must stay above the depth-N rules: both set the cell background, and depth wins. */
:is(vaadin-grid, vaadin-selection-grid).styling::part(odd-row-cell) {
  background-color: color-mix(in srgb, var(--lumo-contrast) 2.5%, var(--lumo-base-color));
}

/*
   Indented rows in an SDataList are shaded by how deep they sit, so children read
   apart from their parent and a deeper branch reads apart from the level above it.
   The part name comes from STreeGrid.depthPartName; top-level rows get no part and
   stay on the plain grid background. The contrast tokens are translucent, so they
   layer correctly over the selection highlight in both light and dark themes.
*/
vaadin-selection-grid.styling::part(depth-1) { background-color: var(--lumo-contrast-5pct);  }
vaadin-selection-grid.styling::part(depth-2) { background-color: var(--lumo-contrast-10pct); }
vaadin-selection-grid.styling::part(depth-3) { background-color: var(--lumo-contrast-20pct); }
vaadin-selection-grid.styling::part(depth-4) { background-color: var(--lumo-contrast-30pct); }
vaadin-selection-grid.styling::part(depth-5) { background-color: var(--lumo-contrast-40pct); }

vaadin-grid-cell-content {
  padding: 4px 2px;
}

vaadin-grid.styling::part(numeric) {
  font-family: inherit;
  font-size: var(--lumo-font-size-xs);
  font-variant-numeric: tabular-nums;
}

span.size-xl {
  font-size: var(--lumo-font-size-xl);
}

span.size-l {
  font-size: var(--lumo-font-size-l);
}

span.size-m {
  font-size: var(--lumo-font-size-m);
}

span.size-s {
  font-size: var(--lumo-font-size-s);
}

span.size-xs {
  font-size: var(--lumo-font-size-xs);
}

span.size-xxs {
  font-size: var(--lumo-font-size-xxs);
}

span.wrapped {
  word-wrap: break-word;
  white-space: normal;
  line-height: 1.4;
}

span.right {
  text-align: right;
}

span.pushup {
  margin-top: -18px;
}

span.numeric {
  text-align: right;
  font-variant-numeric: tabular-nums;
}

span.pushup.numeric {
  text-align: right;
  font-variant-numeric: tabular-nums;
}

.red    sabe-slider { --sabe-slider-color: red; }
.orange sabe-slider { --sabe-slider-color: orange; }
.yellow sabe-slider { --sabe-slider-color: #DAA520; }
.green  sabe-slider { --sabe-slider-color: green; }

vaadin-grid-tree-toggle {
  --vaadin-grid-tree-toggle-level-offset: .5em;
}

hr.menu-separator {
  width: 100% !important;
}

.drop-active-target:focus-within,
.drop-active-target[dragover] {
  outline: 2px dashed var(--lumo-primary-color);
  background-color: var(--lumo-primary-color-10pct);
  border-radius: var(--lumo-border-radius-m);
}

vaadin-tabsheet.wrapping-tabs vaadin-tabs {
  --_lumo-tabs-overflow: visible;
  overflow: visible !important;
}

vaadin-tabsheet.wrapping-tabs vaadin-tabs [part="tabs"] {
  flex-wrap: wrap;
  overflow: visible;
}

vaadin-tabsheet.wrapping-tabs vaadin-tabs::before,
vaadin-tabsheet.wrapping-tabs vaadin-tabs::after {
  display: none;
}

vaadin-tabsheet.wrapping-tabs vaadin-tabs [part="back-button"],
vaadin-tabsheet.wrapping-tabs vaadin-tabs [part="forward-button"] {
  display: none;
}

html {
  /* One status palette. Every value is at least 5:1 against white, against a 10%
     tint of itself, against a striped row and against the selected-row highlight;
     the named colours it replaces measured 1.07:1 (yellow) to 4.00:1 (red). */
  --s-status-good:  #15703a;
  --s-status-warn:  #935306;
  --s-status-bad:   #b91c1c;
  --s-status-info:  #1d4ed8;
  --s-status-muted: #556377;

  /* The old hue families (GoldenRod, SteelBlue, MediumSeaGreen, ForestGreen,
     Orange, Grey), darkened until they read as text. */
  --sabe-wo-open:      var(--s-status-warn);
  --sabe-wo-exploded:  #255f8f;
  --sabe-wo-released:  #0d6b63;
  --sabe-wo-inprocess: var(--s-status-good);
  --sabe-wo-closed:    #b03a0b;
  --sabe-wo-archived:  var(--s-status-muted);
  --sabe-wo-unknown:   var(--s-status-muted);
}

/* ---------- WOSTATUS data-list column pill ---------- */
.wostatus-pill {
  display:          inline-flex;
  align-items:      center;
  justify-content:  center;
  /* 40 + 2×6 = 52px, inside the 54px a 70px column leaves after the cell's
     8px side padding. The widest label (UNKN) is 37.4px. */
  min-width:        40px;
  padding:          1px 6px;
  background:       color-mix(in srgb, var(--wo-state, var(--s-status-muted)) 10%, var(--lumo-base-color));
  border-radius:    999px;
}
.wostatus-pill-label {
  font-size:            var(--lumo-font-size-xs);
  font-variant-numeric: tabular-nums;
  font-weight:          600;
  letter-spacing:       0.04em;
  color:                var(--wo-state, var(--lumo-body-text-color));
  line-height:          1.2;
}

/* state palette — pulls from the global --sabe-wo-* variables */
.wostatus-pill.state-open       { --wo-state: var(--sabe-wo-open);      }
.wostatus-pill.state-exploded   { --wo-state: var(--sabe-wo-exploded);  }
.wostatus-pill.state-released   { --wo-state: var(--sabe-wo-released);  }
.wostatus-pill.state-inprocess  { --wo-state: var(--sabe-wo-inprocess); }
.wostatus-pill.state-closed     { --wo-state: var(--sabe-wo-closed);    }
.wostatus-pill.state-archived   { --wo-state: var(--sabe-wo-archived);  }
.wostatus-pill.state-unknown    { --wo-state: var(--sabe-wo-unknown);  }

/* ---------- STATUS data-list column: constraint status (ConstraintStatusBar) ----------
   The reading users already know: the alert icon is the centre and both bars grow out from it.
   The buffer bar runs from 0% at the far left to 100%, the top of green, at the
   centre - pale below the level, full zone colour from the level to the centre.
   The stock bar fills from the centre out; the rest is pale red. Sized to fill the
   104px STATUS column less 2px of side padding: 13 + 1 + 32 + 14 + 32 + 3 x 2 gaps. */
.cs-bars {
  /* Bars are graphics: 3:1 against white, not text's 4.5:1, so brighter than --s-status-*. */
  --cs-red:        #dc2626;
  --cs-red-dark:   #991b1b;   /* stockout with allocations */
  --cs-yellow:     #eab308;   /* hue 45, still yellow; the fill's edge holds it on white */
  --cs-green:      #16a34a;
  --cs-blue:       #2563eb;
  --cs-blue-dark:  #1e40af;   /* excess with orders */
  --cs-gray:       #cbd5e1;   /* no buffering */

  /* One lightness for the pale bands (OKLCH L 0.94, the pale yellow's), each hue at
     the chroma it holds there. A plain mix with white leaves red darker than yellow,
     and it reads as salmon rather than pale red. */
  --cs-red-pale:    #ffe4e0;
  --cs-yellow-pale: #f9ebbf;
  --cs-green-pale:  #daf3dd;

  display:        inline-flex;
  align-items:    center;
  gap:            2px;
  height:         18px;
  vertical-align: middle;
}

.cs-icon    { width: 14px; height: 14px; flex: none; }
.cs-mode    { width: 13px; height: 13px; margin-right: 1px; color: var(--lumo-secondary-text-color); }
.cs-alert   { color: var(--s-status-bad); }
.cs-warning { color: #b8860b; }   /* DarkGoldenrod: reads yellow, not brown, at 3.25:1 */
.cs-ok      { color: var(--s-status-good); }
.cs-ready   { color: var(--s-status-info); }
.cs-blank   { visibility: hidden; }

.cs-track {
  position:      relative;
  flex:          none;
  width:         32px;
  height:        12px;
  border-radius: 6px;
  overflow:      hidden;
}
.cs-stock { background: var(--cs-red-pale); }

/* The band edges at 33% and 66% are ConstraintStatus.TOPOFRED and TOPOFYELLOW. */
.cs-zoned {
  background: linear-gradient(to right,
    var(--cs-red-pale) 0 33%, var(--cs-yellow-pale) 33% 66%, var(--cs-green-pale) 66% 100%);
}
.cs-level {
  position:      absolute;
  inset:         0;
  border-radius: 6px;
  background:    linear-gradient(to right, var(--cs-red) 0 33%, var(--cs-yellow) 33% 66%, var(--cs-green) 66% 100%);
  clip-path:     inset(0 0 0 var(--level) round 6px);
}

.cs-fill {
  position:      absolute;
  inset:         0 auto 0 0;
  width:         100%;
  border-radius: 6px;
}

/* A soft edge on the full-colour parts only: drawn over a pale band, grey turns the
   pale red tan. */
.cs-level,
.cs-fill { box-shadow: inset 0 0 0 1px rgb(0 0 0 / 0.14); }

.cs-fill.cs-red       { background-color: var(--cs-red);       }
.cs-fill.cs-red-dark  { background-color: var(--cs-red-dark);  }
.cs-fill.cs-yellow    { background-color: var(--cs-yellow);    }
.cs-fill.cs-green     { background-color: var(--cs-green);     }
.cs-fill.cs-blue      { background-color: var(--cs-blue);      }
.cs-fill.cs-blue-dark { background-color: var(--cs-blue-dark); }
.cs-fill.cs-gray      { background-color: var(--cs-gray);      }

/* "With allocations" and "with orders" differ from their plain forms by texture as
   well as shade. */
.cs-striped {
  background-image: repeating-linear-gradient(135deg, rgb(255 255 255 / 0.45) 0 2px, transparent 2px 5px);
}

/* ---------- RQSTATUS data-list column marker icons ---------- */
.rqstatus-markers {
  display:          inline-flex;
  align-items:      center;
  justify-content:  center;
  gap:              4px;
}
.rqstatus-marker {
  width:            var(--lumo-icon-size-s);
  height:           var(--lumo-icon-size-s);
  color:            var(--lumo-primary-text-color);
}

/* Insets are white cards: hairline border, soft shadow, 8px radius. */
.inset-with-caption {
    position: relative;
    background: var(--lumo-base-color);
    border: 1px solid rgb(15 23 42 / 0.08);
    border-radius: 8px;
    box-shadow: 0 1px 2px rgb(15 23 42 / 0.05), 0 1px 3px rgb(15 23 42 / 0.08);
    padding: var(--lumo-space-m);
}

.inset-caption {
    position: absolute;
    top: calc(var(--lumo-font-size-xs) * -0.5);
    left: var(--lumo-space-s);
    background: var(--lumo-base-color);
    padding: 0 var(--lumo-space-xs);
    line-height: 1;
}

/* An SVert caption is the card's title rather than a notch in its border.
   Scoped to the direct child because SReportSelector puts .inset-caption on a
   whole layout, which must keep the rule above. */
.inset-with-caption > .inset-caption {
    position: static;
    background: none;
    padding: 0 var(--lumo-space-s) var(--lumo-space-xs);
    font-size: var(--lumo-font-size-l);
    font-weight: 600;
    letter-spacing: -0.005em;
    color: var(--lumo-header-text-color);
}

.inset,
.inset-without-caption {
    position: relative;
    background: var(--lumo-base-color);
    border: 1px solid rgb(15 23 42 / 0.08);
    border-radius: 8px;
    box-shadow: 0 1px 2px rgb(15 23 42 / 0.05), 0 1px 3px rgb(15 23 42 / 0.08);
    padding: 2px;
}

.s-view {
	border-top: 3px solid var(--sabe-instance-tint, transparent);
}

.s-view__instance-badge {
  position: absolute;
  top:      0.5rem;
  right:    0.5rem;
}

.s-modal__header {
  background-color: color-mix(in srgb,
  var(--sabe-instance-tint, transparent) 18%,
   var(--s-surface));
}

.s-save-icon  { color: var(--lumo-success-text-color); }
.s-abort-icon { color: var(--lumo-error-text-color); }

vaadin-button[disabled] .s-save-icon,
vaadin-button[disabled] .s-abort-icon {
  color: var(--lumo-disabled-text-color);
}

/*
 * SProgress is opened for every dispatch, because it is what blocks interaction while the
 * request is in flight - but most dispatches return in tens of milliseconds and would
 * otherwise flash an overlay on screen. Hold it invisible for its first fraction of a
 * second: a short call is over before anything is painted, and a slow one fades in.
 *
 * This is presentation only. Modality applies from the moment the dialog opens, so the
 * user is blocked throughout regardless of what is visible. Drop the animation to have it
 * appear immediately.
 */
@keyframes s-progress-appear {
  to { opacity: 1; }
}

vaadin-dialog-overlay.s-progress::part(overlay),
vaadin-dialog-overlay.s-progress::part(backdrop),
.s-progress::part(overlay),
.s-progress::part(backdrop) {
  opacity: 0;
  animation: s-progress-appear 0s 400ms forwards;
}