/* ===========================================================================
   UPGEAR visual system — token layer
   ---------------------------------------------------------------------------
   Generated from the UPGEAR Visual System brand book. Section numbers in the
   comments below point back at it.

   This file only DECLARES the system. It deliberately does not repaint the
   Serenity chrome: the tokens are global, the typography and components are
   opt-in under .ug-brand, so a screen joins the system when it asks to. That
   keeps the 5,301 line vendor theme out of the blast radius while the rollout
   is module by module.
   =========================================================================== */

/* ---------------------------------------------------------------------------
   13 · Primary palette — violet 6647F0, nine steps, nine neutrals
   Three of the nine steps are the faces of the mark and keep those names here.
   Never fake a tint with opacity over a coloured background: pick the step.
   --------------------------------------------------------------------------- */
:root {
  --ug-v-50: #F3F1FD;   /* tint wash */
  --ug-v-100: #E4DFFA;  /* selected row */
  --ug-v-200: #CBC1F7;  /* chart fill, prior periods */
  --ug-v-300: #B7A9FF;  /* light face · Up · text on ink */
  --ug-v-400: #7B68EE;  /* mid face · Right · 18px text and up */
  --ug-v-500: #6647F0;  /* core · primary action, focus ring */
  --ug-v-600: #4A2FC9;  /* dark face · Base · links, hover */
  --ug-v-700: #3D22B0;  /* GEAR on white */
  --ug-v-800: #241463;  /* deep surface, press state */

  --ug-white: #FFFFFF;    /* cards, tables */
  --ug-canvas: #F6F5FB;   /* page ground */
  --ug-sunken: #F0EEF9;   /* wells, inputs */
  --ug-line: #EAE7F5;     /* hairlines */
  --ug-grey-400: #8B86A8; /* disabled only, 3.5:1 */
  --ug-grey-500: #6C6784; /* labels, meta — the smallest text allowed */
  --ug-grey-700: #4A465C; /* body copy */
  --ug-ink: #16141F;      /* headings, values */
  --ug-night: #0B0A16;    /* marketing ground */

  /* -------------------------------------------------------------------------
     14 · Secondary palette — one hue per trade
     A trade takes one hue and inherits the same three values at the same three
     positions in the mark. Masterbrand material stays violet, so a prospect can
     always tell the company from one of its trades.
     ------------------------------------------------------------------------- */
  --ug-teal-300: #5FD4C3;
  --ug-teal-500: #0E9E8C;  /* pest control — non-text use only, 3.3:1 */
  --ug-teal-700: #065C52;  /* the value to use when teal has to carry text */
  --ug-cobalt-500: #2F6BFF;  /* facility management */
  --ug-amber-500: #F5871F;   /* AC service */
  --ug-rose-500: #E4457E;    /* deep cleaning */
  --ug-lime-500: #5AA326;    /* reserved, fifth trade */

  /* -------------------------------------------------------------------------
     15 · Functional colours — five states, each darker and less saturated than
     the trade hues so a teal chrome and a green cleared chip cannot be confused.
     Allowed on a dot, a chip, a 4px bar or text. Never on a card or a page.
     Every state carries its word beside the dot.
     ------------------------------------------------------------------------- */
  --ug-cleared: #14804A;   /* paid, closed, reconciled, signed off — 5.0:1 */
  --ug-due: #966000;       /* inside the window, needs someone today — 5.3:1 */
  --ug-overdue: #C2352A;   /* past the window, money or proof at risk — 5.5:1 */
  --ug-system: #4A2FC9;    /* automation acted, or waits for approval — 8.3:1 */
  --ug-inactive: #6C6784;  /* paused, draft, archived — 5.4:1 */

  /* 17 · Typefaces — three families, two scripts */
  --ug-font-display: 'Archivo', 'Segoe UI', system-ui, sans-serif;
  --ug-font-body: 'IBM Plex Sans', 'Segoe UI', system-ui, sans-serif;
  --ug-font-mono: 'IBM Plex Mono', ui-monospace, 'Cascadia Mono', Consolas, monospace;
  --ug-font-deva: 'IBM Plex Sans Devanagari', 'Nirmala UI', sans-serif;

  /* 20 · Spacing — ten steps. A value between two steps is wrong. */
  --ug-space-1: 4px;    /* optical nudge inside a component */
  --ug-space-2: 8px;    /* label to value, icon to text */
  --ug-space-3: 12px;   /* between fields in a form group */
  --ug-space-4: 16px;   /* between cards in a grid */
  --ug-space-5: 24px;   /* gutter, card padding on mobile */
  --ug-space-6: 28px;   /* card padding on desktop */
  --ug-space-7: 40px;   /* between blocks in a section */
  --ug-space-8: 56px;   /* product page top padding */
  --ug-space-9: 80px;   /* between sections */
  --ug-space-10: 120px; /* full-bleed change of ground */

  /* 22 · Shapes — two families, and exactly one elevation */
  --ug-radius-chip: 8px;
  --ug-radius-button: 10px;
  --ug-radius-panel: 16px;
  --ug-radius-card: 24px;
  --ug-shadow: 0 1px 2px rgba(22, 20, 31, 0.07);
  --ug-shadow-modal: 0 24px 50px -28px rgba(22, 20, 31, 0.45);

  /* 27 · Motion — one easing curve, two durations */
  --ug-ease: cubic-bezier(.2, .9, .25, 1);
  --ug-dur-state: 160ms;
  --ug-dur-entry: 240ms;
}

/* A trade module sets its own hue by adding .ug-trade-pest to the page root.
   The three positions never change: light carries Up, mid carries Right, dark
   carries Base, in every hue, so every mark reads as lit from the upper left. */
.ug-trade-pest {
  --ug-trade-300: var(--ug-teal-300);
  --ug-trade-500: var(--ug-teal-500);
  --ug-trade-700: var(--ug-teal-700);
}

/* Violet is the masterbrand default wherever no trade owns the surface. */
:root {
  --ug-trade-300: var(--ug-v-300);
  --ug-trade-500: var(--ug-v-500);
  --ug-trade-700: var(--ug-v-600);
}

/* ---------------------------------------------------------------------------
   18 · Type hierarchy — product scale, 14px floor
   Scoped to .ug-brand so joining the system is a decision a screen makes.
   --------------------------------------------------------------------------- */
.ug-brand {
  font-family: var(--ug-font-body);
  font-size: 14px;
  line-height: 1.45;
  color: var(--ug-grey-700);
}

.ug-brand :lang(hi) {
  font-family: var(--ug-font-deva);
  /* Devanagari takes 0.1 more line-height than Latin at the same size. */
  line-height: 1.55;
}

.ug-page-title {
  font-family: var(--ug-font-display);
  font-weight: 700;
  font-size: 24px;
  line-height: 1.16;
  letter-spacing: -0.028em;
  color: var(--ug-ink);
  margin: 0;
}

.ug-section-heading {
  font-family: var(--ug-font-body);
  font-weight: 600;
  font-size: 18px;
  line-height: 1.3;
  color: var(--ug-ink);
  margin: 0;
}

.ug-field-label {
  font-family: var(--ug-font-body);
  font-weight: 500;
  font-size: 12.5px;
  color: var(--ug-grey-500);
}

.ug-meta {
  font-family: var(--ug-font-body);
  font-size: 12px;
  color: var(--ug-grey-500);
}

/* Section labels are the one place Plex Mono is set in caps. */
.ug-label {
  font-family: var(--ug-font-mono);
  font-weight: 500;
  font-size: 10px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--ug-grey-500);
}

/* The dispute rule: any figure a customer could dispute goes in mono. Rupees,
   dates, counts, IDs, percentages. Tabular lining so columns align. */
.ug-num,
.ug-mono {
  font-family: var(--ug-font-mono);
  font-size: 13px;
  font-variant-numeric: tabular-nums lining-nums;
  font-feature-settings: 'tnum' 1, 'lnum' 1;
  color: var(--ug-ink);
}

.ug-num { text-align: right; }

/* ---------------------------------------------------------------------------
   24 · Iconography — 24 box, 20 live, 1.75 stroke for the interface set.
   30 / 31 · The two Lottie sets ride in .ug-icon. Base colour rides on
   currentColor so it flips to white on a dark surface; the teal highlight is
   fixed and stays teal.
   --------------------------------------------------------------------------- */
.ug-icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: 0 0 auto;
  color: var(--ug-ink);
  vertical-align: middle;
}

.ug-icon > svg,
.ug-icon > .ug-icon-svg {
  width: 100%;
  height: 100%;
  display: block;
}

/* 30 · Sizes in use. Below 20px the stroke closes the counters, so the trade
   set is not drawn smaller than a table row. */
.ug-icon-row   { width: 20px; height: 20px; }
.ug-icon-card  { width: 28px; height: 28px; }
.ug-icon-tile  { width: 44px; height: 44px; }
.ug-icon-empty { width: 72px; height: 72px; }

/* The soft green ground both sets are presented on. */
.ug-icon-ground {
  background: #F2FAF8;
  border-radius: var(--ug-radius-button);
  padding: var(--ug-space-2);
}

.ug-icon-on-dark { color: var(--ug-white); }

/* ---------------------------------------------------------------------------
   23 · Graphic devices — four, and no more. A fifth is a change to the brand
   book rather than a decision inside a project.
   --------------------------------------------------------------------------- */

/* The mark's three faces flattened into a rule. Always in the hue of whatever
   it belongs to, so the bar itself says company or trade. */
.ug-bar {
  display: block;
  height: 4px;
  border-radius: 2px;
  background: linear-gradient(
    to right,
    var(--ug-trade-300) 0 33.333%,
    var(--ug-trade-500) 33.333% 66.667%,
    var(--ug-trade-700) 66.667% 100%);
}

/* A 16px corner cut marks anything that is evidence: a proof card, a
   certificate seal, a timestamped photograph. The only decoration in the
   system, and it is load-bearing. */
.ug-cut {
  clip-path: polygon(0 0, calc(100% - 16px) 0, 100% 16px, 100% 100%, 0 100%);
}

/* Chips joined by a 1px line, left to right, current record in the brand hue.
   The chain never loops back on itself visually, even when the cycle does. */
.ug-chain {
  display: flex;
  align-items: center;
  gap: 0;
  flex-wrap: wrap;
}

.ug-chain-link {
  font-family: var(--ug-font-body);
  font-size: 12px;
  font-weight: 500;
  color: var(--ug-grey-500);
  background: var(--ug-white);
  border: 1px solid var(--ug-line);
  border-radius: var(--ug-radius-chip);
  padding: 3px 10px;
  white-space: nowrap;
}

.ug-chain-link.is-current {
  color: var(--ug-white);
  background: var(--ug-trade-500);
  border-color: var(--ug-trade-500);
}

.ug-chain-link + .ug-chain-link { position: relative; margin-left: 13px; }

.ug-chain-link + .ug-chain-link::before {
  content: '';
  position: absolute;
  left: -13px;
  top: 50%;
  width: 13px;
  height: 1px;
  background: var(--ug-line);
}

/* ---------------------------------------------------------------------------
   15 · State chips. The word rule: every state carries its word beside the dot,
   because a technician on a washed-out screen has to act with the colour gone.
   --------------------------------------------------------------------------- */
.ug-state {
  display: inline-flex;
  align-items: center;
  gap: var(--ug-space-2);
  font-family: var(--ug-font-body);
  font-size: 12px;
  font-weight: 500;
  color: var(--ug-grey-700);
}

.ug-state::before {
  content: '';
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: currentColor;
  flex: 0 0 auto;
}

.ug-state-cleared  { color: var(--ug-cleared); }
.ug-state-due      { color: var(--ug-due); }
.ug-state-overdue  { color: var(--ug-overdue); }
.ug-state-system   { color: var(--ug-system); }
.ug-state-inactive { color: var(--ug-inactive); }

/* ---------------------------------------------------------------------------
   22 · Surfaces
   --------------------------------------------------------------------------- */
.ug-card {
  background: var(--ug-white);
  border: 1px solid var(--ug-line);
  border-radius: var(--ug-radius-card);
  box-shadow: var(--ug-shadow);
  padding: var(--ug-space-6);
}

.ug-panel {
  background: var(--ug-white);
  border: 1px solid var(--ug-line);
  border-radius: var(--ug-radius-panel);
}

/* 22 · A full circle means a person. Avatars, the operator, the customer.
   Nothing else is round. */
.ug-person {
  border-radius: 50%;
  overflow: hidden;
  flex: 0 0 auto;
}

/* ---------------------------------------------------------------------------
   27 · Accessibility — focus is never removed, including on mouse. Targets are
   44px on the field app because the technician is wearing gloves.
   --------------------------------------------------------------------------- */
.ug-brand :focus-visible {
  outline: 2px solid var(--ug-v-500);
  outline-offset: 2px;
  border-radius: 3px;
}

@media (prefers-reduced-motion: reduce) {
  .ug-brand *,
  .ug-brand *::before,
  .ug-brand *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
  }
}

/* ===========================================================================
   06 · Motion conversion — hold, hollow, stand, run
   ---------------------------------------------------------------------------
   The mark never moves and never changes size. It hollows out. Same frame,
   same scale, same position, start to finish, and nothing crossfades into
   anything. The three solid faces empty into the rim that already bounded
   them, the socket's negative space becomes a chest, and the circle they were
   holding stands up.

   The rim draws over the body, never under it. That single z-order decision is
   what makes the operator stand inside the business rather than in front of
   it, and it is what turns the boundary into a shield.
   =========================================================================== */
.ug-film {
  --ug-film-loop: 7600ms;
  --ug-film-hue-300: var(--ug-v-300);
  --ug-film-hue-500: var(--ug-v-400);
  --ug-film-hue-700: var(--ug-v-600);
  --ug-film-body: var(--ug-v-300);
  /* No face, no hands, no gender, no name. Head is white on dark and ink on light. */
  --ug-film-head: var(--ug-ink);
  --ug-film-light: var(--ug-white);
  display: block;
  width: 120px;
  height: 120px;
}

.ug-film--reversed { --ug-film-head: var(--ug-white); }

.ug-film--pest {
  --ug-film-hue-300: var(--ug-teal-300);
  --ug-film-hue-500: var(--ug-teal-500);
  --ug-film-hue-700: var(--ug-teal-700);
  --ug-film-body: var(--ug-teal-300);
}

.ug-film .ug-film-face-a { fill: var(--ug-film-hue-300); }
.ug-film .ug-film-face-b { fill: var(--ug-film-hue-500); }
.ug-film .ug-film-face-c { fill: var(--ug-film-hue-700); }
.ug-film .ug-film-rim { stroke: var(--ug-film-hue-500); fill: none; stroke-width: 0; }
.ug-film .ug-film-spark { stroke: var(--ug-film-light); fill: none; stroke-width: 7; opacity: 0; }
.ug-film .ug-film-chest { fill: var(--ug-film-body); }
.ug-film .ug-film-head { fill: var(--ug-film-head); }
.ug-film .ug-film-limb {
  stroke: var(--ug-film-body);
  stroke-width: 8;
  stroke-linecap: round;
  fill: none;
}

/* Beat 1 · Hold, 0–680ms. The mark, doing nothing. Long enough to be read as
   the logo before it is read as an animation. Beat 2 · Hollow, 680–1450ms. */
.ug-film .ug-film-faces { animation: ug-hollow var(--ug-film-loop) var(--ug-ease) infinite; }

/* The rim arrives and overshoots to weight 11.5 before settling to 7. */
.ug-film .ug-film-rim { animation: ug-rim var(--ug-film-loop) var(--ug-ease) infinite; }

/* The head is the circle that was sitting in the socket, moved up the vertical
   axis. Nothing is invented to make the figure. */
.ug-film .ug-film-head {
  transform-box: view-box;
  animation: ug-head var(--ug-film-loop) var(--ug-ease) infinite;
}

/* Beat 3 · Stand, 1450–2100ms. Limbs draw, the chest arrives, and a 5% scale
   pop lands after the rim settles so the sequence ends on the person. */
.ug-film .ug-film-body-group {
  transform-box: view-box;
  transform-origin: 60px 60px;
  animation: ug-stand var(--ug-film-loop) var(--ug-ease) infinite;
}
.ug-film .ug-film-limb {
  stroke-dasharray: 100;
  stroke-dashoffset: 100;
  animation: ug-limbs var(--ug-film-loop) var(--ug-ease) infinite;
}

/* Beat 4 · Run, 2100ms onward. The light travels the rim at constant speed and
   does not stop. This is the sustain, and it is the idle state of the brand. */
.ug-film .ug-film-spark {
  /* The hexagon perimeter is six sides of 48. */
  stroke-dasharray: 48 240;
  animation:
    ug-spark-run 2100ms linear infinite,
    ug-spark-in var(--ug-film-loop) steps(1) infinite;
}

@keyframes ug-hollow {
  0%, 8.95% { opacity: 1; }
  19.08%, 100% { opacity: 0; }
}

@keyframes ug-rim {
  0%, 8.95% { stroke-width: 0; }
  15.13% { stroke-width: 11.5; }
  19.08%, 100% { stroke-width: 7; }
}

@keyframes ug-head {
  0%, 11.84% { transform: translateY(0); }
  21.05%, 100% { transform: translateY(-34px); }
}

@keyframes ug-stand {
  0%, 19.08% { opacity: 0; transform: scale(1); }
  22% { opacity: 1; transform: scale(1); }
  25% { transform: scale(1.05); }
  27.63%, 100% { opacity: 1; transform: scale(1); }
}

@keyframes ug-limbs {
  0%, 19.08% { stroke-dashoffset: 100; }
  27.63%, 100% { stroke-dashoffset: 0; }
}

@keyframes ug-spark-run {
  from { stroke-dashoffset: 288; }
  to { stroke-dashoffset: 0; }
}

@keyframes ug-spark-in {
  0%, 27.62% { opacity: 0; }
  27.63%, 100% { opacity: 1; }
}

/* The loader cut: the film at 2.8s without the limbs. The mark hollows, the
   head lifts, the light runs, repeat. */
.ug-film--loader { --ug-film-loop: 2800ms; }
.ug-film--loader .ug-film-limb { display: none; }

/* Below roughly 32px the limbs merge into the torso, so the figure is not used
   at that size. Use the folded mark. */
.ug-film--fold .ug-film-faces,
.ug-film--fold .ug-film-head { animation: none; }
.ug-film--fold .ug-film-body-group,
.ug-film--fold .ug-film-rim,
.ug-film--fold .ug-film-spark { display: none; }

/* 27 · Under prefers-reduced-motion the master film holds on beat one and
   nothing else plays. */
@media (prefers-reduced-motion: reduce) {
  .ug-film .ug-film-faces,
  .ug-film .ug-film-rim,
  .ug-film .ug-film-head,
  .ug-film .ug-film-body-group,
  .ug-film .ug-film-limb,
  .ug-film .ug-film-spark { animation: none; }
  .ug-film .ug-film-faces { opacity: 1; }
  .ug-film .ug-film-body-group,
  .ug-film .ug-film-rim,
  .ug-film .ug-film-spark { display: none; }
}

/* ===========================================================================
   The header band
   ---------------------------------------------------------------------------
   The band keeps the blue hue and the left-to-right direction it always had, but
   sits deeper than the original. The constraint driving it is the mark rather
   than taste: its three faces are #B7A9FF, #7B68EE and #4A2FC9, so the ground
   has to sit clearly outside that range or two of them dissolve into it. The
   original blue (#2f7fae to #4b9bc9) landed right in the middle of it, which is
   why the mark read as a light blob there.

   Grounds tried and rejected on the way here: ink, white, masterbrand violet at
   full strength, a white plate behind the mark, the one-colour white silhouette,
   a deep navy that read as black, a light blue, a light aqua, and V-100 from the
   violet ramp.

   Two things stay unresolved and are recorded in TASKS.md. The book refuses
   enterprise blue outright, and a violet mark on a blue ground is two hues in
   one composition. The place to settle both is the wider chrome repaint.
   =========================================================================== */
/* The gradient runs light to dark rather than the other way round, so the lightest
   end sits behind the mark. That end is #22689A, which lands between the mark's
   dark face (#4A2FC9) and its mid face (#7B68EE) in luminance, so both separate
   against it and the light face has clear air. Ten percent lighter than this was
   tried and dropped; it also took white text down to 4.84:1, close enough to the
   AA floor that any further lift would force the whole header to ink. */
.s-sidebar-header {
  background: linear-gradient(90deg, #22689A 0%, #1C5A87 45%, #123A5E 100%);
}

/* The old rule ringed the logo in white and rounded it, which was drawn for a
   square bitmap. A hexagon loses its points to that, so the ring and the radius
   go and the mark sits on the band with nothing behind it.

   34px in a 48px band leaves 7px above and below, which is a little over 0.5x of
   the mark's width. That is the floor the book allows for clear space in an app
   bar, so this is as large as the mark goes here. */
.s-sidebar-header-logo {
  width: 34px;
  height: 34px;
  background: none;
  border-radius: 0;
  padding: 0;
  box-shadow: none;
}


/* Serenity's login/form title logo is a coloured disc built for a knocked-out
   white logo. The Hex Drive is drawn to stand on its own ground, and a circular
   crop takes the points off it, so the disc goes. */
.s-form-title-logo {
  background-color: transparent;
  border-radius: 0;
  padding: 0;
}

/* ---------------------------------------------------------------------------
   Bootstrap primaries on a page that has opted in. Scoped to .ug-brand so this
   never reaches the Serenity chrome; a page joins the system by asking to.
   --------------------------------------------------------------------------- */
.ug-brand .btn-primary {
  --bs-btn-bg: var(--ug-v-500);
  --bs-btn-border-color: var(--ug-v-500);
  --bs-btn-hover-bg: var(--ug-v-600);
  --bs-btn-hover-border-color: var(--ug-v-600);
  --bs-btn-active-bg: var(--ug-v-800);
  --bs-btn-active-border-color: var(--ug-v-800);
  --bs-btn-disabled-bg: var(--ug-grey-400);
  --bs-btn-disabled-border-color: var(--ug-grey-400);
  border-radius: var(--ug-radius-button);
  font-weight: 600;
}

.ug-brand .btn-outline-primary {
  --bs-btn-color: var(--ug-v-600);
  --bs-btn-border-color: var(--ug-line);
  --bs-btn-hover-bg: var(--ug-v-50);
  --bs-btn-hover-color: var(--ug-v-600);
  --bs-btn-hover-border-color: var(--ug-v-300);
  --bs-btn-active-bg: var(--ug-v-100);
  --bs-btn-active-color: var(--ug-v-600);
  --bs-btn-active-border-color: var(--ug-v-300);
  border-radius: var(--ug-radius-button);
  font-weight: 600;
}

/* A trade screen takes its own hue for the action, so a pest-control page does
   not put violet chrome next to teal content. */
.ug-brand.ug-trade-pest .btn-primary,
.ug-brand .ug-trade-pest .btn-primary {
  --bs-btn-bg: var(--ug-trade-700);
  --bs-btn-border-color: var(--ug-trade-700);
  --bs-btn-hover-bg: var(--ug-ink);
  --bs-btn-hover-border-color: var(--ug-ink);
  --bs-btn-active-bg: var(--ug-ink);
  --bs-btn-active-border-color: var(--ug-ink);
}

.ug-brand.ug-trade-pest .btn-outline-primary {
  --bs-btn-color: var(--ug-trade-700);
  --bs-btn-hover-color: var(--ug-trade-700);
  --bs-btn-hover-bg: #F2FAF8;
  --bs-btn-hover-border-color: var(--ug-trade-300);
  --bs-btn-active-color: var(--ug-trade-700);
  --bs-btn-active-bg: #F2FAF8;
  --bs-btn-active-border-color: var(--ug-trade-300);
}
