/* ==========================================================================
   LOGIN — Pawaskar Engineering ERP

   Two panes: an animated brand stage on the left, the sign-in card on the
   right. On a phone the stage collapses to a compact header so the form is
   reachable without scrolling.

   The page is LIGHT. That is a consequence of the logo, not a taste call:
   the mark is fixed blue artwork, so the surface under it has to be the thing
   that gives way. Recolouring the logo to survive a dark ground would have
   been the wrong way round.

   Everything here is self-contained CSS. No canvas, no animation library,
   no image beyond the existing logo - the login screen is the one page that
   must render instantly on a bad connection, and it is also the page most
   likely to be seen by someone evaluating the company.

   Motion rules followed throughout:
     - only transform / opacity / filter are animated, so every frame stays
       off the layout and paint path
     - interaction feedback lands in 150-300ms; ambient motion is slow
       (14-30s) so it reads as atmosphere rather than distraction
     - the whole ambient layer is switched off under prefers-reduced-motion
   ========================================================================== */

:root{
  /* Taken from the Pawaskar Engineering logo (#1257FF) so the page and the
     mark are the same blue rather than two blues that nearly agree. The
     lighter and darker steps are that same hue, moved in lightness only. */
  --brand:        #1257ff;
  --brand-bright: #4d82ff;
  --brand-deep:   #0b3fcc;
  /* The cyan is darkened from #22d3ee: that value was picked to glow on a
     near-black ground and turns to pale mist on a light one. */
  --accent:       #0891b2;

  /* LIGHT GROUND.

     The logo is fixed blue artwork, so the surface under it is what gives
     way - a light page lets the mark appear in its own colour instead of
     being recoloured to survive a dark one. Not flat white: a trace of the
     brand hue runs through all three steps, so the page reads as chosen with
     the logo rather than as default white. */
  --bg-0: #e8eefb;
  --bg-1: #f5f8ff;
  --bg-2: #ffffff;

  --card:        #ffffff;
  --card-solid:  #ffffff;
  --hairline:    rgba(18,24,43,0.10);

  /* Ink and ground swap roles with the palette. #5a6784 on these grounds is
     ~5.9:1, past the 4.5:1 body-text floor with room to spare. */
  --ink:      #12182b;
  --ink-soft: #5a6784;
  --ink-dark: #12182b;

  /* The overlay colour for hairlines, veils and inset surfaces. On the old
     dark page every one of these was white at a low alpha; on a light page
     they have to be ink instead, or they vanish. Kept as a token so there is
     one place to change if the ground ever moves again. */
  --veil: 18,24,43;

  --r-lg: 26px;
  --r-md: 16px;
  --r-sm: 11px;
}

*{ margin:0; padding:0; box-sizing:border-box; }

html, body{ height:100%; }

body{
  font-family:'Inter', system-ui, -apple-system, 'Segoe UI', sans-serif;
  background: var(--bg-0);
  color: var(--ink);
  font-size:16px;
  line-height:1.5;
  /* The stage paints past the viewport edges; without this the drifting
     aurora would hand the page a horizontal scrollbar. */
  overflow-x:hidden;
  -webkit-font-smoothing:antialiased;
}

a{ color:inherit; }

.shell{
  display:grid;
  grid-template-columns: 1.15fr 0.85fr;
  min-height:100vh;
}

/* ======================================================== LEFT: BRAND STAGE */

.stage{
  position:relative;
  overflow:hidden;
  padding:56px 60px;
  display:flex;
  flex-direction:column;
  justify-content:space-between;
  background:
    radial-gradient(1200px 800px at 15% 12%, rgba(18,87,255,0.14), transparent 60%),
    radial-gradient(900px 700px at 85% 85%,  rgba(8,145,178,0.10), transparent 60%),
    linear-gradient(160deg, var(--bg-2) 0%, var(--bg-1) 45%, var(--bg-0) 100%);
}

/* --- ambient layer 1: drifting aurora ------------------------------------
   Three large blurred ellipses on long, mismatched loops. The periods are
   deliberately coprime-ish (23s/29s/37s) so the composite never visibly
   repeats - a single shared period reads as a loop within about a minute. */
.aurora{ position:absolute; inset:-25%; pointer-events:none; }
.aurora span{
  position:absolute;
  border-radius:50%;
  filter: blur(90px);
  opacity:.5;
  will-change: transform;
}
.aurora span:nth-child(1){
  width:46%; height:46%; top:6%; left:4%;
  background: radial-gradient(circle, rgba(18,87,255,.30), transparent 70%);
  animation: drift-a 23s ease-in-out infinite;
}
.aurora span:nth-child(2){
  width:40%; height:40%; top:46%; left:44%;
  background: radial-gradient(circle, rgba(8,145,178,.22), transparent 70%);
  animation: drift-b 29s ease-in-out infinite;
}
.aurora span:nth-child(3){
  width:34%; height:34%; top:24%; left:56%;
  background: radial-gradient(circle, rgba(77,130,255,.22), transparent 70%);
  animation: drift-c 37s ease-in-out infinite;
}
@keyframes drift-a{
  0%,100%{ transform: translate3d(0,0,0) scale(1); }
  50%    { transform: translate3d(14%, 10%, 0) scale(1.18); }
}
@keyframes drift-b{
  0%,100%{ transform: translate3d(0,0,0) scale(1.1); }
  50%    { transform: translate3d(-16%, -12%, 0) scale(0.9); }
}
@keyframes drift-c{
  0%,100%{ transform: translate3d(0,0,0) scale(0.95); }
  50%    { transform: translate3d(-10%, 14%, 0) scale(1.2); }
}

/* --- ambient layer 2: engineering grid ----------------------------------
   Masked to fade out toward the edges so it never fights the content. */
.grid-veil{
  position:absolute; inset:0; pointer-events:none;
  background-image:
    linear-gradient(rgba(var(--veil),.055) 1px, transparent 1px),
    linear-gradient(90deg, rgba(var(--veil),.055) 1px, transparent 1px);
  background-size:56px 56px;
  -webkit-mask-image: radial-gradient(ellipse 78% 68% at 42% 42%, #000 35%, transparent 100%);
          mask-image: radial-gradient(ellipse 78% 68% at 42% 42%, #000 35%, transparent 100%);
}

/* --- ambient layer 3: the precision schematic -----------------------------
   A rotating spindle assembly on a drawing-office grid. This firm rebuilds
   machines and spindles, so the backdrop is the work rather than an abstract
   node graph.

   The teeth are stroke-dasharray on a plain circle: at this size and opacity
   a dashed ring reads as a gear, and it costs no path data. Only transform is
   animated, so the whole layer composites on the GPU. */
.schematic{
  position:absolute; inset:0; width:100%; height:100%;
  pointer-events:none; opacity:.5;
}

.schematic .gear{ transform-box: fill-box; transform-origin:center; }
.schematic .teeth{
  fill:none;
  stroke: rgba(18,87,255,.30);
  stroke-width:22;
  /* the dash pattern IS the tooth pitch - longer gap than dash keeps it
     legible rather than closing up into a solid ring */
  stroke-dasharray: 12 26;
}
.schematic .rim{
  fill:none; stroke: rgba(18,87,255,.20); stroke-width:1.5;
}
.schematic .spokes line{
  stroke: rgba(18,87,255,.18); stroke-width:2;
}
.schematic .hub{ fill: rgba(18,87,255,.20); }

/* Meshed pair: the small gear must turn the other way, or the picture is
   mechanically wrong to anyone who works on these for a living. */
.gear-lg{ animation: turn 46s linear infinite; }
.gear-sm{ animation: turn 30s linear infinite reverse; }
@keyframes turn{ to{ transform: rotate(360deg); } }

/* Centrelines and datum crosses, the way a shop drawing is dimensioned. */
.schematic .datum line,
.schematic .datum path{
  stroke: rgba(18,87,255,.14); stroke-width:1; fill:none;
}
.schematic .datum .centre{ stroke-dasharray: 26 8 4 8; }

/* --- stage content ------------------------------------------------------- */
.stage-inner{ position:relative; z-index:2; }

.brandmark{ display:flex; align-items:center; gap:15px; }

/* Shown exactly as supplied - no filter, no recolouring. The stage was made
   light precisely so the mark could keep its own blue. */
.brandmark img{
  height:40px; width:auto;
}

.headline{ margin-top:auto; padding:46px 0 34px; max-width:610px; }
.eyebrow{
  display:inline-flex; align-items:center; gap:9px;
  padding:7px 15px; border-radius:999px;
  background: rgba(77,124,255,.13);
  border:1px solid rgba(77,124,255,.3);
  font-size:.76rem; font-weight:600; letter-spacing:.06em; text-transform:uppercase;
  color: var(--brand-deep);
}
.eyebrow .dot{
  width:7px; height:7px; border-radius:50%; background:#34d399;
  box-shadow:0 0 0 0 rgba(52,211,153,.65);
  animation: livedot 2.4s ease-out infinite;
}
@keyframes livedot{
  0%  { box-shadow:0 0 0 0 rgba(52,211,153,.6); }
  70% { box-shadow:0 0 0 11px rgba(52,211,153,0); }
  100%{ box-shadow:0 0 0 0 rgba(52,211,153,0); }
}

.headline h1{
  margin-top:22px;
  font-size: clamp(2rem, 3.5vw, 3.15rem);
  font-weight:800;
  letter-spacing:-.032em;
  line-height:1.08;
}
.headline h1 .grad{
  background: linear-gradient(100deg, var(--brand) 0%, var(--brand-deep) 50%, var(--accent) 100%);
  -webkit-background-clip:text; background-clip:text;
  -webkit-text-fill-color:transparent;
  /* 200% background + a slow slide = the sheen crosses the words without
     animating anything the compositor has to re-lay-out. */
  background-size:200% auto;
  animation: sheen 7s ease-in-out infinite;
}
@keyframes sheen{
  0%,100%{ background-position:0% center; }
  50%    { background-position:100% center; }
}

.headline p{
  margin-top:17px; font-size:1.03rem; color:var(--ink-soft); max-width:520px;
}

/* Rotating capability line. Each item is absolutely stacked and cycles on a
   shared 12s timeline with 3s slots, so they hand over cleanly. */
.rotator{
  position:relative; height:30px; margin-top:24px;
  font-size:.96rem; font-weight:600; color: var(--ink-soft);
}
/* Five services now, not four: the cycle is 5 x 3s and each item owns 20% of
   it. Leaving this at the old 12s/25% would have shown four of them and
   silently dropped the fifth. */
.rotator span{
  position:absolute; inset:0;
  display:flex; align-items:center; gap:10px;
  opacity:0; transform:translateY(10px);
  animation: rot 15s cubic-bezier(.22,.61,.36,1) infinite;
}
.rotator span i{ color:var(--accent); }
.rotator span:nth-child(1){ animation-delay:0s; }
.rotator span:nth-child(2){ animation-delay:3s; }
.rotator span:nth-child(3){ animation-delay:6s; }
.rotator span:nth-child(4){ animation-delay:9s; }
.rotator span:nth-child(5){ animation-delay:12s; }
@keyframes rot{
  0%   { opacity:0; transform:translateY(10px); }
  3%,17%{ opacity:1; transform:translateY(0); }
  20%,100%{ opacity:0; transform:translateY(-10px); }
}

/* --- the floating console ------------------------------------------------
   A suggestion of the product rather than a screenshot: a screenshot dates
   the moment the UI changes, this does not. */
/* Anchored to the TOP right, not vertically centred. The headline is pushed
   to the bottom of the stage by margin-top:auto, so a centred console landed
   on top of the first line of the h1 at desktop widths - the top-right
   quadrant is the only genuinely free space here. */
.console{
  position:absolute; right:44px; top:104px;
  width:290px; z-index:2;
  border-radius:var(--r-md);
  /* The job card stays dark on the light stage - deliberately. It is a
     read-out from the shop floor, and giving it the contrast of an instrument
     panel is what separates it from the page it floats over.

     Because it is the one dark surface left, the ink tokens are re-declared
     here rather than overridden rule by rule. Custom properties inherit, so
     every descendant - the step list, the machine name, the percentage -
     picks up the light-on-dark set without a single extra selector. */
  --ink:      #ffffff;
  --ink-soft: #9fb0cc;
  --veil:     255,255,255;

  background: #101a33;
  color: var(--ink);
  border:1px solid rgba(18,87,255,.35);
  box-shadow:0 26px 54px -22px rgba(18,24,43,.45);
  overflow:hidden;
  animation: bob 9s ease-in-out infinite;
}
@keyframes bob{
  0%,100%{ transform:translate3d(0,0,0); }
  50%    { transform:translate3d(-6px,-12px,0); }
}
.console-bar{
  display:flex; align-items:center; gap:6px;
  padding:11px 14px; border-bottom:1px solid var(--hairline);
  background:rgba(var(--veil),.03);
}
.console-bar i{ width:9px; height:9px; border-radius:50%; display:inline-block; }
.console-bar .r{ background:#ff5f57; } .console-bar .y{ background:#febc2e; } .console-bar .g{ background:#28c840; }
.console-bar b{ margin-left:8px; font-size:.72rem; font-weight:600; color:var(--ink-soft); }

.console-body{ padding:16px 16px 18px; }

/* --- proof strip --------------------------------------------------------- */
.proof{
  position:relative; z-index:2;
  display:flex; gap:38px; flex-wrap:wrap;
  padding-top:26px; border-top:1px solid rgba(var(--veil),.09);
}
.proof div .n{ font-size:1.28rem; font-weight:800; letter-spacing:-.02em; }
.proof div .l{ font-size:.74rem; color:var(--ink-soft); margin-top:2px; }

/* ======================================================== RIGHT: SIGN IN */

/* The right half was a near-black slab: a flat #070b16 with a 10% glow over
   it reads as dead space, and a 5.5%-white card floating on it is barely
   there at all - backdrop-filter has nothing to blur when the surface behind
   is a flat colour, so the "glass" simply did not register.

   So the panel now carries real depth of its own (deep navy base, two
   brand glows, and the same grid the stage uses so the two halves read as
   one page), and the card sits on it as a genuinely raised surface. */
.panel{
  position:relative;
  display:flex; align-items:center; justify-content:center;
  padding:44px 46px;
  background:
    radial-gradient(760px 560px at 82% -6%, rgba(47,87,230,.30), transparent 60%),
    radial-gradient(620px 520px at 6% 106%, rgba(34,211,238,.16), transparent 62%),
    linear-gradient(165deg, #101a35 0%, #0a1024 46%, #070c1c 100%);
  border-left:1px solid rgba(var(--veil),.08);
  overflow:hidden;
}

/* Grid carried across from the stage, faded toward the centre so it never
   competes with the form. */
.panel::before{
  content:''; position:absolute; inset:0; pointer-events:none;
  background-image:
    linear-gradient(rgba(var(--veil),.04) 1px, transparent 1px),
    linear-gradient(90deg, rgba(var(--veil),.04) 1px, transparent 1px);
  background-size:56px 56px;
  -webkit-mask-image: radial-gradient(ellipse 70% 60% at 50% 50%, transparent 30%, #000 100%);
          mask-image: radial-gradient(ellipse 70% 60% at 50% 50%, transparent 30%, #000 100%);
}

/* Brand halo directly behind the card, so it sits in a pool of light rather
   than on a black rectangle. */
.panel::after{
  content:''; position:absolute; z-index:0;
  width:520px; height:520px; top:50%; left:50%;
  transform:translate(-50%,-50%);
  border-radius:50%;
  background: radial-gradient(circle, rgba(47,87,230,.22), transparent 68%);
  filter: blur(50px);
  pointer-events:none;
}

.card{
  position:relative; z-index:1;
  width:100%; max-width:392px;
  /* Solid white on the light ground. The glass treatment this replaced only
     worked over a dark stage - translucent ink over a pale page turns the
     card grey and drops the form's contrast with it. */
  background: var(--card-solid);
  border:1px solid rgba(var(--veil),.09);
  border-radius: var(--r-lg);
  padding:38px 34px 30px;
  box-shadow:
    0 24px 54px -24px rgba(18,24,43,.28),   /* lift off the panel */
    0 0 0 1px rgba(18,87,255,.06);          /* faint brand ring */
  animation: rise .55s cubic-bezier(.2,.7,.3,1) both;
}
@keyframes rise{
  from{ opacity:0; transform:translateY(16px); }
  to  { opacity:1; transform:translateY(0); }
}

/* Islahlogo.png is a transparent RGBA file whose wordmark is already the
   brand blue and whose orbit mark is the brand red - both read cleanly on
   the dark card, so it goes straight onto the surface. Boxing it in a white
   plate (as the old OnTrack .jpg needed) would put a bright rectangle in the
   middle of the design for no reason. */
.card-logo{ text-align:center; margin-bottom:20px; }
.card-logo img{
  /* The logo is a wide wordmark (241x64 source, ~3.75:1), so it is sized by
     width and given more of it than the old square mark had. Its own blue is
     kept here - the card is light, which is what that colour is drawn for. */
  width:210px; max-width:100%; height:auto;
  display:inline-block;
}

.card h2{
  font-size:1.32rem; font-weight:700; letter-spacing:-.02em; text-align:center;
}
.card .sub{
  text-align:center; color:var(--ink-soft); font-size:.87rem; margin-top:5px; margin-bottom:24px;
}

/* Visible labels, not placeholder-only: a placeholder disappears the moment
   someone types, which is exactly when a person tabbing back through a form
   needs to know which field they are in. */
.field{ margin-bottom:16px; }
.field label{
  display:block; font-size:.79rem; font-weight:600;
  color: var(--ink); margin-bottom:7px; letter-spacing:.01em;
}
.field .wrap{ position:relative; }
.field .wrap > i.lead{
  position:absolute; left:14px; top:50%; transform:translateY(-50%);
  color:#7d8db0; font-size:.9rem; pointer-events:none; transition:color .2s ease;
}
.field .form-control{
  width:100%;
  height:48px;                      /* comfortably past the 44px touch floor */
  padding:0 14px 0 40px;
  font-size:.95rem; color:var(--ink);
  background: rgba(var(--veil),.045);
  border:1px solid rgba(var(--veil),.14);
  border-radius: var(--r-sm);
  transition: border-color .2s ease, background .2s ease, box-shadow .2s ease;
}
.field .form-control::placeholder{ color:#63739a; }
.field .form-control:focus{
  outline:none;
  background: rgba(var(--veil),.075);
  border-color: var(--brand-bright);
  box-shadow:0 0 0 3px rgba(77,124,255,.22);
}
.field .wrap:focus-within > i.lead{ color:var(--brand-bright); }

/* The shared password-toggle utility injects its button at the input's right
   edge and reserves 38px of padding. Recolour it for a dark field - its own
   stylesheet assumes a light one. */
.field .pw-toggle-btn{ color:#7d8db0 !important; }
.field .pw-toggle-btn:hover{ color:var(--ink) !important; }

.btn-signin{
  width:100%; height:48px; margin-top:6px;
  border:0; border-radius: var(--r-sm);
  font-size:.95rem; font-weight:700; letter-spacing:.01em; color:#ffffff;
  background: linear-gradient(120deg, var(--brand-deep), var(--brand) 55%, var(--brand-bright));
  background-size:180% auto;
  cursor:pointer;
  transition: background-position .35s ease, transform .15s ease, box-shadow .25s ease;
  box-shadow:0 12px 26px -12px rgba(18,87,255,.30);
}
.btn-signin:hover{ background-position:right center; box-shadow:0 16px 32px -12px rgba(18,87,255,.55); }
.btn-signin:active{ transform:translateY(1px); }
.btn-signin:focus-visible{ outline:2px solid var(--brand-bright); outline-offset:3px; }
.btn-signin[disabled]{ opacity:.72; cursor:default; }

.secure{
  display:flex; align-items:center; justify-content:center; gap:7px;
  margin-top:18px; font-size:.76rem; color: var(--ink-soft);
}
.secure i{ color:#34d399; }

.card-foot{
  margin-top:22px; padding-top:17px;
  border-top:1px solid rgba(var(--veil),.09);
  text-align:center; font-size:.75rem; color: var(--ink-soft); line-height:1.75;
}
.card-foot a{ color:#a9c0ee; font-weight:600; text-decoration:none; }
.card-foot a:hover{ color: var(--ink); text-decoration:underline; }

/* Credit line for Islah Data Consultancy - the firm that built this. */
.built{
  display:inline-flex; align-items:center; gap:7px;
  margin-top:9px; padding:6px 13px; border-radius:999px;
  background:rgba(var(--veil),.05); border:1px solid rgba(var(--veil),.1);
  font-size:.74rem; color: var(--ink-soft); text-decoration:none;
  transition: background .2s ease, border-color .2s ease, transform .2s ease;
}
.built:hover{
  background:rgba(18,87,255,.10); border-color:rgba(18,87,255,.34);
  transform:translateY(-1px); color: var(--brand-deep); text-decoration:none;
}
.built i{ color:var(--brand-bright); }

/* Alerts from Auth.js land in #dvResponse, which is Bootstrap markup - give
   it enough styling to sit on a dark card. */
#dvResponse .alert{
  border-radius:var(--r-sm); font-size:.85rem; padding:11px 14px; margin-bottom:16px;
  border:1px solid transparent;
}
#dvResponse .alert-danger{ background:rgba(220,38,38,.14); border-color:rgba(248,113,113,.4); color:#fecaca; }
#dvResponse .alert-success{ background:rgba(16,185,129,.14); border-color:rgba(52,211,153,.4); color:#bbf7d0; }
#dvResponse .alert .close{ color:inherit; opacity:.65; background:none; border:0; float:right; font-size:1.1rem; cursor:pointer; }

/* Parsley error text, same reason. */
.parsley-errors-list{ list-style:none; margin:6px 0 0; padding:0; font-size:.76rem; color:#fca5a5; }

/* ============================================================== RESPONSIVE */

@media (max-width: 1180px){
  .console{ display:none; }              /* reclaim the width for the headline */
}

@media (max-width: 980px){
  .shell{ grid-template-columns:1fr; }
  .stage{
    padding:34px 30px 40px;
    min-height:auto;
  }
  .headline{ padding:30px 0 26px; }
  .headline h1{ font-size:clamp(1.65rem, 6vw, 2.3rem); }
  .headline p{ font-size:.95rem; }
  .proof{ gap:26px; }
  .panel{
    padding:34px 24px 46px;
    border-left:0; border-top:1px solid rgba(var(--veil),.07);
  }
}

@media (max-width: 560px){
  .stage{ padding:26px 20px 32px; }
  .rotator{ font-size:.88rem; }
  .proof div .n{ font-size:1.1rem; }
  .card{ padding:30px 22px 26px; }
}

/* Ambient motion is decoration; a user who has asked for less of it should
   get a still page, not a slower one. Interaction feedback (focus, hover,
   button press) deliberately survives - that is information, not ornament. */
@media (prefers-reduced-motion: reduce){
  .aurora span, .schematic .gear,
  .headline h1 .grad, .rotator span, .console,
  .job-steps li.live span, .job-progress i,
  .eyebrow .dot, .card{
    animation:none !important;
  }
  .rotator span{ opacity:0; }
  .rotator span:nth-child(1){ opacity:1; }
  /* The bar carries its value in `width`, so switching the animation off
     leaves it showing 62% rather than empty - nothing to restore here. */
  .card{ opacity:1; transform:none; }
}

/* ==========================================================================
   JOB CARD CONSOLE

   The floating panel on the stage. It shows one job moving along the bench,
   which is what this system exists to track - the panel it replaced showed a
   sales pipeline in rupees, inherited from the CRM this was forked from.
   ========================================================================== */

.job-head{ display:flex; align-items:center; justify-content:space-between; gap:10px; }
.job-machine{ font-size:.94rem; font-weight:700; letter-spacing:-.01em; }
.job-pill{
  flex:none;
  font-size:.62rem; font-weight:700; text-transform:uppercase; letter-spacing:.07em;
  padding:4px 9px; border-radius:999px;
  color:#8ff0d0;
  background: rgba(52,211,153,.14);
  border:1px solid rgba(52,211,153,.34);
}
.job-client{ font-size:.72rem; color:var(--ink-soft); margin-top:3px; }

/* The bench route. Each step is a dot on a rail, so where the job has got to
   is readable at a glance without reading any of the words. */
.job-steps{
  list-style:none; margin:16px 0 0; padding:0;
  display:flex; flex-direction:column; gap:9px;
  position:relative;
}
.job-steps li{
  position:relative; padding-left:22px;
  font-size:.74rem; color:var(--ink-soft);
}
.job-steps li span{
  position:absolute; left:0; top:50%; transform:translateY(-50%);
  width:9px; height:9px; border-radius:50%;
  background: rgba(var(--veil),.14);
  box-shadow: 0 0 0 2px rgba(var(--veil),.05);
}
/* the rail joining the dots */
.job-steps li:not(:last-child)::after{
  content:""; position:absolute; left:4px; top:calc(50% + 6px);
  width:1px; height:9px; background: rgba(var(--veil),.12);
}
.job-steps li.done{ color: var(--ink-soft); }
.job-steps li.done span{ background: var(--brand-bright); box-shadow:0 0 0 2px rgba(77,130,255,.2); }
.job-steps li.live{ color: var(--ink); font-weight:600; }
.job-steps li.live span{
  background:#34d399;
  box-shadow:0 0 0 3px rgba(52,211,153,.22);
  animation: jobPulse 2.4s ease-in-out infinite;
}
@keyframes jobPulse{
  0%,100%{ box-shadow:0 0 0 3px rgba(52,211,153,.22); }
  50%    { box-shadow:0 0 0 7px rgba(52,211,153,0); }
}

.job-progress{
  height:5px; border-radius:999px; margin-top:16px;
  background: rgba(var(--veil),.09); overflow:hidden;
}
/* The width is the value (62%); the animation only scales it in from the left.

   Written this way for two reasons. Animating `width` would run layout on
   every frame, which the rest of this file deliberately avoids - transform
   and opacity only. And because the width is static, the bar reads correctly
   even when the animation never runs at all: a background tab freezes its
   timeline, and reduced-motion switches it off outright. Animating width
   would leave the bar empty in both of those cases. */
.job-progress i{
  display:block; height:100%; width:62%; border-radius:999px;
  background: linear-gradient(90deg, var(--brand-bright), var(--accent));
  transform-origin:left;
  animation: jobFill 2.6s cubic-bezier(.22,.61,.36,1) both;
}
@keyframes jobFill{ from{ transform:scaleX(0); } to{ transform:scaleX(1); } }

.job-foot{
  display:flex; align-items:center; justify-content:space-between;
  margin-top:9px; font-size:.68rem; color:var(--ink-soft);
}
.job-pct{ font-weight:700; color: var(--ink-soft); }
