/* Employee portal. Inherits the site's tokens from styles.css; this file only
   adds what a working application needs on top of a marketing page.

   The public site is a page you read top to bottom. This is a tool people use
   on a shift, so it is laid out as an application: a fixed rail of
   destinations on the left, one working surface on the right, and no scrolling
   to find the thing you came to press. */

.portal-body { background: var(--paper); }

/* ------------------------------------------------------------------ shell */

.pshell { display: flex; min-height: 100vh; min-height: 100dvh; }

.pside {
  position: sticky;
  top: 0;
  align-self: flex-start;
  flex: 0 0 232px;
  height: 100vh;
  height: 100dvh;
  display: flex;
  flex-direction: column;
  padding: 22px 14px 16px;
  background: var(--paper-2);
  border-right: 1px solid var(--line);
  z-index: 50;
}

/* The mark alone, sitting on the same left edge as the destinations below it.
   The rail pads 14px and each destination pads another 11 inside that, so the
   mark is inset to match: an icon that starts left of everything it sits above
   reads as a mistake, not as a logo. */
.pside-brand {
  display: block;
  width: max-content;
  padding: 2px 11px 22px;
  text-decoration: none;
  color: var(--ink);
}
.pside-brand .nav-mark { width: 42px; }

.pnav { display: flex; flex-direction: column; gap: 2px; overflow-y: auto; }
.pnav-h {
  font-family: var(--mono); font-size: 9.5px; letter-spacing: 0.16em;
  text-transform: uppercase; color: var(--ink-3);
  padding: 16px 10px 7px;
}
.pnav-h[hidden] { display: none; }

.pnav-i {
  display: flex;
  align-items: center;
  gap: 11px;
  width: 100%;
  font-family: var(--nav); font-size: 14.5px; font-weight: 500;
  text-align: left;
  color: var(--ink-2);
  background: none;
  border: 0;
  border-radius: 10px;
  padding: 10px 11px;
  cursor: pointer;
  transition: background 0.16s ease, color 0.16s ease;
}
.pnav-i[hidden] { display: none; }
.pnav-i svg {
  width: 17px; height: 17px; flex: 0 0 auto;
  fill: none; stroke: currentColor; stroke-width: 1.6;
  stroke-linecap: round; stroke-linejoin: round;
  opacity: 0.75;
}
.pnav-i:hover { color: var(--ink); background: rgba(255, 255, 255, 0.05); }
.pnav-i.is-on { color: var(--paper); background: var(--ink); }
.pnav-i.is-on svg { opacity: 1; }

.pside-foot { margin-top: auto; padding-top: 18px; }
.pside-lang { display: flex; margin: 0 0 10px; }
.pside-lang .lang-b { flex: 1; text-align: center; }
.login-lang { display: inline-flex; align-self: flex-start; margin-top: 24px; }

.pwho {
  display: flex; align-items: center; gap: 10px;
  padding: 10px 10px 14px;
}
/* Initials rather than a photo: nobody is uploading one from a fuel truck, and
   two letters are enough to be sure you are looking at your own account. */
.pwho-av {
  flex: 0 0 auto;
  width: 32px; height: 32px; border-radius: 50%;
  display: grid; place-items: center;
  font-family: var(--nav); font-size: 12.5px; font-weight: 600;
  color: var(--ink);
  background: rgba(255, 255, 255, 0.09);
  border: 1px solid var(--line);
}
.pwho-t { display: grid; gap: 2px; min-width: 0; }
.pwho-n {
  font-family: var(--nav); font-size: 13.5px; font-weight: 500; color: var(--ink);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.pwho-r {
  font-family: var(--mono); font-size: 9.5px; letter-spacing: 0.13em;
  text-transform: uppercase; color: var(--ink-3);
}

.pmain { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; }

/* ------------------------------------------------------------------- top */

.ptop {
  position: sticky;
  top: 0;
  z-index: 40;
  display: flex;
  align-items: center;
  gap: 14px;
  padding: 12px clamp(16px, 3vw, 34px);
  background: rgba(10, 11, 13, 0.86);
  backdrop-filter: blur(18px);
  -webkit-backdrop-filter: blur(18px);
  /* No rule under the bar. It was drawing a line across the top of a page
     whose first element is already a heading, which is a border doing the job
     a heading was doing anyway. The blur is what separates the bar from what
     scrolls under it. */
}
.ptop-k {
  font-family: var(--mono); font-size: 9.5px; letter-spacing: 0.15em;
  text-transform: uppercase; color: var(--ink-3); margin-bottom: 5px;
}
.ptop-h {
  font-family: var(--display); font-size: clamp(19px, 2.3vw, 25px);
  font-weight: 700; letter-spacing: -0.015em; line-height: 1;
}
.ptop-spacer { margin-left: auto; }

.pstatus {
  display: inline-flex; align-items: center; gap: 9px;
  font-family: var(--mono); font-size: 10.5px; letter-spacing: 0.11em;
  text-transform: uppercase; color: var(--ink-2);
  border: 1px solid var(--line); border-radius: 999px; padding: 7px 14px;
  font-variant-numeric: tabular-nums;
}
.pstatus.is-on { color: var(--ink); border-color: rgba(255, 255, 255, 0.34); }

/* three lines, becoming a cross once the rail is out */
.pside-btn {
  display: none;
  width: 38px; height: 38px; padding: 0; border: 0;
  border-radius: 50%; background: rgba(255, 255, 255, 0.08);
  color: var(--ink); cursor: pointer; flex: 0 0 auto;
}
.pside-btn span {
  display: block; width: 16px; height: 1.5px; margin: 3px auto;
  background: currentColor; border-radius: 2px;
  transition: transform 0.24s ease, opacity 0.18s ease;
}
.pshell.is-open .pside-btn span:nth-child(1) { transform: translateY(4.5px) rotate(45deg); }
.pshell.is-open .pside-btn span:nth-child(2) { opacity: 0; }
.pshell.is-open .pside-btn span:nth-child(3) { transform: translateY(-4.5px) rotate(-45deg); }

.pscrim {
  position: fixed; inset: 0; z-index: 45;
  background: rgba(0, 0, 0, 0.55);
  backdrop-filter: blur(2px);
}
.pscrim[hidden] { display: none; }

/* 1180 rather than 1500. This is a form and a set of readings, not a table of
   figures — past about this width the columns stop being denser and just get
   further apart, and three tiles holding "0:00" end up 400px wide each. The
   top padding is small because the greeting is the first thing and it does not
   need to be pushed down the page to be noticed. */
.pwrap {
  flex: 1 1 auto;
  padding: 10px clamp(16px, 3vw, 34px) 80px;
  max-width: 1180px;
  width: 100%;
}
.pview[hidden] { display: none; }

/* ------------------------------------------------------------------ pieces */

.pcard {
  background: var(--paper-2);
  border: 1px solid var(--line);
  border-radius: 16px;
  padding: clamp(18px, 2.2vw, 26px);
}
.pcard-quiet { background: transparent; }
.pcard-top { display: flex; align-items: center; gap: 14px; flex-wrap: wrap; margin-bottom: 14px; }
.pcard-top .btn { margin-left: auto; }

.pgrid { display: grid; gap: 16px; }
.pgrid.two { grid-template-columns: repeat(auto-fit, minmax(320px, 1fr)); }
.pgrid.stats { grid-template-columns: repeat(auto-fit, minmax(180px, 1fr)); }

.phead {
  font-family: var(--mono); font-size: 10.5px; letter-spacing: 0.14em;
  text-transform: uppercase; color: var(--ink-3); margin-bottom: 14px;
}

.stat-n {
  font-family: var(--display); font-size: clamp(28px, 3.4vw, 42px);
  font-weight: 700; letter-spacing: -0.02em; line-height: 1;
  font-variant-numeric: tabular-nums;
}
.stat-l { margin-top: 8px; font-family: var(--nav); font-size: 13px; color: var(--ink-2); }

/* clock */
.pcard-clock { display: flex; flex-direction: column; }
.clock-state { display: flex; align-items: center; gap: 12px; margin-bottom: 8px; }
.clock-dot { width: 9px; height: 9px; border-radius: 50%; background: var(--ink-3); flex: 0 0 auto; }
.clock-dot.is-on { background: #fff; box-shadow: 0 0 0 4px rgba(255, 255, 255, 0.14); }

/* A running clock is the one number on this page that changes while you look
   at it, so it is set at the size of a headline and in tabular figures: the
   digits must not shuffle sideways every second. */
.clock-since {
  font-family: var(--display); font-size: clamp(34px, 5vw, 56px);
  font-weight: 700; letter-spacing: -0.03em; line-height: 1;
  font-variant-numeric: tabular-nums;
}
.clock-since.is-idle { color: var(--ink-3); }
.clock-sub { font-family: var(--nav); font-size: 13.5px; color: var(--ink-2); margin-top: 8px; }
.clock-acts { margin-top: auto; padding-top: 22px; display: flex; gap: 10px; flex-wrap: wrap; }

/* forms */
.pform { display: grid; gap: 15px; }
.prow { display: grid; grid-template-columns: repeat(auto-fit, minmax(160px, 1fr)); gap: 15px; }

.field { display: grid; gap: 7px; }
.field-l {
  font-family: var(--mono); font-size: 10px; letter-spacing: 0.12em;
  text-transform: uppercase; color: var(--ink-2);
}
.field-wrap { position: relative; display: block; }
.field-wrap input { width: 100%; padding-right: 66px; }
.field-eye {
  position: absolute; top: 50%; right: 8px; transform: translateY(-50%);
  font-family: var(--mono); font-size: 9.5px; letter-spacing: 0.11em;
  text-transform: uppercase; color: var(--ink-2);
  background: none; border: 0; border-radius: 7px; padding: 7px 8px; cursor: pointer;
}
.field-eye:hover { color: var(--ink); background: rgba(255, 255, 255, 0.07); }
.field-hint { font-family: var(--nav); font-size: 12.5px; color: var(--ink-2); }
.field-hint[hidden] { display: none; }

.pform input, .pform select, .pform textarea {
  font-family: var(--nav); font-size: 15px; color: var(--ink);
  background: var(--paper); border: 1px solid var(--line);
  border-radius: 10px; padding: 12px 13px; outline: none;
  transition: border-color 0.16s ease, box-shadow 0.16s ease;
}
.pform input::placeholder, .pform textarea::placeholder { color: var(--ink-3); }
.pform input:focus, .pform select:focus, .pform textarea:focus {
  border-color: rgba(255, 255, 255, 0.5);
  box-shadow: 0 0 0 3px rgba(255, 255, 255, 0.07);
}
.pform textarea { resize: vertical; min-height: 74px; }

.btn {
  font-family: var(--nav); font-size: 14.5px; font-weight: 500;
  padding: 12px 20px; border-radius: 999px; cursor: pointer;
  border: 1px solid rgba(255, 255, 255, 0.28); background: transparent; color: var(--ink);
  transition: background 0.16s ease, opacity 0.16s ease, border-color 0.16s ease;
}
.btn:hover { background: rgba(255, 255, 255, 0.09); }
.btn.solid { background: var(--ink); color: var(--paper); border-color: var(--ink); }
.btn.solid:hover { opacity: 0.86; background: var(--ink); }
.btn.ghost { border-color: var(--line); color: var(--ink-2); }
.btn.ghost:hover { color: var(--ink); border-color: rgba(255, 255, 255, 0.3); }
.btn.wide { width: 100%; }
.btn.slim { padding: 8px 14px; font-size: 13px; }
/* A grid stretches its children, and a submit pill the width of the form reads
   as a banner rather than as a button. The sign-in door is the exception: one
   field, one action, nothing to aim at but that. */
.pform > .btn { justify-self: start; }
.login-form > .btn { justify-self: stretch; }
.btn:disabled { opacity: 0.4; cursor: not-allowed; }

/* tables */
.ptable-wrap { overflow-x: auto; }
.ptable { width: 100%; border-collapse: collapse; font-family: var(--nav); font-size: 14px; min-width: 720px; }
.ptable th {
  font-family: var(--mono); font-size: 10px; font-weight: 500; letter-spacing: 0.12em;
  text-transform: uppercase; text-align: left; color: var(--ink-2);
  padding: 10px 14px 10px 0; border-bottom: 1px solid var(--ink);
  position: sticky; top: 0; background: var(--paper-2);
}
.ptable td { padding: 12px 14px 12px 0; border-bottom: 1px solid var(--line); color: var(--ink-2); vertical-align: top; }
.ptable td.n { text-align: right; padding-right: 0; font-variant-numeric: tabular-nums; color: var(--ink); font-weight: 500; }
.ptable tr.is-void td { opacity: 0.45; text-decoration: line-through; }
.ptable .who { color: var(--ink); font-weight: 500; }

.pill {
  display: inline-block; font-family: var(--mono); font-size: 9.5px;
  letter-spacing: 0.12em; text-transform: uppercase;
  border: 1px solid var(--line); border-radius: 999px; padding: 3px 8px; color: var(--ink-2);
}
.pill.on { color: var(--ink); border-color: rgba(255, 255, 255, 0.5); }

.pmsg { font-family: var(--nav); font-size: 13.5px; padding: 11px 14px; border-radius: 10px; border: 1px solid var(--line); }
.pmsg.bad { border-color: rgba(255, 255, 255, 0.4); color: var(--ink); }
.pmsg.good { border-color: rgba(255, 255, 255, 0.28); color: var(--ink-2); }
.pmsg[hidden] { display: none; }

.pempty { font-family: var(--nav); font-size: 14px; color: var(--ink-3); padding: 26px 0; }

.ptools { display: flex; gap: 10px; align-items: center; flex-wrap: wrap; margin-bottom: 16px; }
.ptools input, .ptools select {
  font-family: var(--nav); font-size: 14px; color: var(--ink);
  background: var(--paper-2); border: 1px solid var(--line);
  border-radius: 10px; padding: 10px 13px; outline: none;
}
.ptools input:focus, .ptools select:focus { border-color: rgba(255, 255, 255, 0.4); }

/* ------------------------------------------------------------------- login */

/* Two panels: the ramp on one side so the door looks like the place it opens
   onto, the form on the other. Below the breakpoint the photograph goes rather
   than shrinking to a stripe, because a phone screen is all form. */
.login { min-height: 100vh; min-height: 100dvh; display: grid; grid-template-columns: 1.05fr 1fr; }

.login-plate { position: relative; overflow: hidden; background: #000; }
/* A truck being fuelled, which is the job, rather than an aircraft, which is
   the customer. The people signing in here work the hose. */
.login-shot {
  position: absolute; inset: 0;
  background: url('../assets/portal-plate.jpg') center / cover no-repeat;
  filter: grayscale(1) contrast(1.06) brightness(0.58);
  transform: scale(1.03);
}
.login-grain {
  position: absolute; inset: -50%;
  background: url('../assets/grain.png') repeat;
  opacity: 0.16; mix-blend-mode: overlay; pointer-events: none;
}
.login-scrim {
  position: absolute; inset: 0;
  background: linear-gradient(180deg, rgba(0,0,0,0.55) 0%, rgba(0,0,0,0.15) 40%, rgba(0,0,0,0.88) 100%);
}
.login-plate-copy { position: absolute; left: clamp(28px, 4vw, 56px); right: clamp(28px, 4vw, 56px); bottom: clamp(30px, 4vw, 54px); }
.login-plate-eyebrow {
  font-family: var(--mono); font-size: 10px; letter-spacing: 0.16em;
  text-transform: uppercase; color: rgba(255, 255, 255, 0.62); margin-bottom: 12px;
}
.login-plate-line {
  font-family: var(--display); font-size: clamp(28px, 3.4vw, 46px);
  font-weight: 700; text-transform: uppercase; letter-spacing: -0.025em; line-height: 0.98;
}

.login-panel { display: grid; place-items: center; padding: 40px clamp(20px, 4vw, 56px); }
.login-card { width: 100%; max-width: 390px; }

/* The mark on its own, at a size that reads as a mark rather than an icon.
   Nothing else identifies this page, so it carries the whole job. */
.login-brand {
  display: inline-block;
  text-decoration: none;
  color: var(--ink);
  margin-bottom: 40px;
}
.login-mark { width: 78px; }

.login-h {
  font-family: var(--display); font-size: clamp(30px, 3.4vw, 38px);
  font-weight: 700; text-transform: uppercase; letter-spacing: -0.025em; margin-bottom: 8px;
}
.login-sub { font-family: var(--nav); font-size: 14.5px; color: var(--ink-2); margin-bottom: 28px; }
.login-form { gap: 17px; }
.login-foot { margin-top: 26px; display: grid; gap: 16px; justify-items: start; align-self: stretch; }

/* One target, the whole line. A locked-out person is not looking for a number
   to copy down, they are looking for help, so the question dials too. */
/* The question is the link and looks like it: underlined, and out of the dim
   grey a field label wears. The digits used to sit beside it carrying the only
   underline, which said the number was the link and the question a caption —
   the reverse of what the markup does. The digits are gone now; the number is
   in the label, for a screen reader and for anyone who cannot dial from the
   device they are on.

   Kept inline rather than inline-flex so the underline belongs to the text and
   breaks with it, which matters in Spanish where the question is longer. The
   vertical padding moves nothing but enlarges the hit area, worth having on
   the one control a locked-out person on a phone actually needs. */
.login-call {
  display: inline;
  font-family: var(--nav);
  font-size: 14px;
  color: var(--ink-2);
  line-height: 1.9;
  padding: 6px 0;
  text-decoration: underline;
  text-decoration-color: rgba(255, 255, 255, 0.24);
  text-decoration-thickness: 1px;
  text-underline-offset: 5px;
  transition: color 0.16s ease, text-decoration-color 0.16s ease;
}
.login-call:hover,
.login-call:focus-visible {
  color: var(--ink);
  text-decoration-color: var(--ink);
}

.login-back { font-family: var(--nav); font-size: 13px; color: var(--ink-3); }
.login-back:hover { color: var(--ink-2); }

.btn-go { position: relative; margin-top: 4px; padding: 14px 20px; }
.btn-spin {
  display: none;
  width: 14px; height: 14px; margin-left: 10px; vertical-align: -2px;
  border: 1.6px solid rgba(0, 0, 0, 0.28); border-top-color: var(--paper);
  border-radius: 50%;
  animation: pspin 0.7s linear infinite;
}
.btn-go.is-busy .btn-spin { display: inline-block; }
@keyframes pspin { to { transform: rotate(360deg); } }

/* the handover, drawn over the card once the password is accepted */
.login-pass {
  position: fixed; inset: 0; z-index: 60;
  display: grid; place-items: center; align-content: center; gap: 20px;
  background: var(--paper);
}
.login-pass[hidden] { display: none; }
.login-pass-mark { width: 74px; }
.login-pass-t {
  font-family: var(--mono); font-size: 10.5px; letter-spacing: 0.2em;
  text-transform: uppercase; color: var(--ink-2);
}

/* ------------------------------------------------------------------ narrow */

/* Below the split, the photograph does not go away: it moves behind the form
   and fills the screen. Hiding it was the easy answer and the wrong one, since
   the phone is where most people sign in and it left them a black box. The
   scrim below carries the contrast the type needs. */
@media (max-width: 980px) {
  .login { grid-template-columns: 1fr; position: relative; }
  .login-plate {
    position: fixed;
    inset: 0;
    z-index: 0;
  }
  .login-plate-copy { display: none; }

  /* Light at the top so the photograph is a photograph, heavy where the form
     sits so the type has something solid under it. */
  .login-scrim {
    background: linear-gradient(180deg,
      rgba(10, 11, 13, 0.34) 0%,
      rgba(10, 11, 13, 0.60) 14%,
      rgba(10, 11, 13, 0.94) 34%,
      rgba(10, 11, 13, 0.99) 100%);
  }
  .login-shot { filter: grayscale(1) contrast(1.04) brightness(0.66); }

  /* The card fills the panel and splits: the mark pinned to the top edge, the
     form resting on the bottom. Bottom-aligning the whole card left the mark
     wherever the content happened to end, so it drifted with the length of the
     copy and never sat on a line of its own. */
  /* The gap under the mark is a set distance rather than whatever is left
     over, so the card is its own natural height. That means it can simply be
     centred: pinning it to the top with a fixed offset moved the dead space to
     the bottom instead of removing it — 81px above the card and 149px below,
     measured, which is what read as sitting too high. Centred, the space falls
     evenly on both sides at any height. Padding is the floor, so on a short
     phone the card stops rather than running off the top. */
  .login-panel {
    position: relative;
    z-index: 1;
    align-items: center;
    padding: calc(clamp(24px, 4vh, 48px) + env(safe-area-inset-top)) 20px
             calc(clamp(24px, 4vh, 48px) + env(safe-area-inset-bottom));
  }
  .login-card {
    max-width: none;
    display: flex;
    flex-direction: column;
  }
  .login-brand { margin: 0 0 clamp(34px, 7vh, 64px); }

  /* The brand rides on the picture at the top; the form is a plate resting on
     the dark end of it, so the two read as layers rather than one flat wash. */
  /* Over the bright end of the photograph the mark needs to be lifted off it,
     the way the copy over the hero is. */
  .login-mark { width: 88px; filter: drop-shadow(0 2px 14px rgba(0, 0, 0, 0.6)); }

  .login-h {
    font-size: clamp(30px, 8.6vw, 40px);
    line-height: 0.94;
    text-shadow: 0 2px 20px rgba(0, 0, 0, 0.5);
  }
  .login-sub { margin-bottom: 20px; }
  .login-form { gap: 14px; }
  .login-foot { margin-top: 20px; gap: 12px; }
}

@media (max-width: 900px) {
  /* The rail slides out over the work rather than squeezing it. */
  .pside {
    position: fixed;
    top: 0; bottom: 0; left: 0;
    width: 250px; flex: none;
    transform: translateX(-100%);
    transition: transform 0.28s cubic-bezier(0.22, 1, 0.36, 1);
  }
  .pshell.is-open .pside { transform: none; }

  /* The drawer opens beneath the bar rather than through it. Its own mark was
     landing in the same forty pixels as the menu button, so an open drawer
     showed two round things stacked on each other and neither looked like the
     way out. Content starts below the bar; the button stays above everything
     because while the drawer is open it is the way to close it. */
  .pside { padding-top: 74px; }
  .pside-btn { display: block; position: relative; z-index: 60; }
  .ptop { padding-top: max(14px, env(safe-area-inset-top)); }
  .pstatus { padding: 6px 11px; font-size: 9.5px; }
}

@media (max-width: 700px) {
  .ptable { min-width: 560px; }
  .ptop-k { display: none; }
  .pwrap { padding-bottom: max(60px, env(safe-area-inset-bottom)); }
}

@media (prefers-reduced-motion: reduce) {
  .pside { transition: none; }
  .btn-spin { animation-duration: 2s; }
}

/* ==========================================================================
   The shift page.

   Written for a phone first, because that is where these are filled in: on a
   ramp, one-handed, often in sunlight. Everything below is a single column
   until there is room for more, the actions are large enough to hit without
   looking, and the numbers that answer "am I on the clock and for how long"
   are the biggest things on the screen.
   ========================================================================== */

.shift-top { display: grid; gap: 14px; grid-template-columns: 1fr; }
.shift-side { display: grid; gap: 14px; align-content: start; }

/* ---- the ring ---------------------------------------------------------- */

.ring-wrap {
  position: relative;
  width: min(210px, 62vw);
  margin: 6px auto 2px;
  aspect-ratio: 1;
}
.ring { width: 100%; height: 100%; transform: rotate(-90deg); }
.ring circle { fill: none; stroke-width: 8; }
.ring-bg { stroke: rgba(255, 255, 255, 0.09); }
.ring-fg {
  stroke: var(--ink);
  stroke-linecap: round;
  transition: stroke-dashoffset 0.6s linear;
}
.is-resting .ring-fg { stroke: #e8b83b; }

.ring-mid {
  position: absolute;
  inset: 0;
  display: grid;
  place-content: center;
  text-align: center;
  gap: 2px;
}
.ring-cap {
  margin: 0;
  font-family: var(--nav);
  font-size: 11px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--ink-3);
}
.pcard-clock .clock-since { font-size: clamp(30px, 8vw, 40px); margin: 0; }

/* On a phone the three actions are the reason the page exists, so they are a
   full-width stack rather than a row of small targets. */
.clock-acts { display: grid; gap: 8px; margin-top: 12px; }
.clock-acts .btn { padding: 14px 18px; font-size: 15px; }
.btn.warn { border-color: #e8b83b; color: #e8b83b; }
.btn.warn:hover { background: rgba(232, 184, 59, 0.12); }
.pill.warn { background: rgba(232, 184, 59, 0.16); color: #e8b83b; }

/* ---- the timeline ------------------------------------------------------ */

.tl {
  position: relative;
  height: 34px;
  margin-top: 10px;
  border-radius: 8px;
  background: rgba(255, 255, 255, 0.04);
  overflow: hidden;
}
.tl-track { position: absolute; inset: 0; }
.tl-seg { position: absolute; top: 0; bottom: 0; border-radius: 5px; }
.k-sched { background: rgba(255, 255, 255, 0.11); }
.k-work  { background: rgba(242, 242, 240, 0.62); }
.k-break { background: #e8b83b; opacity: 0.9; }

/* The current time. A line rather than a dot so it reads against a bar of the
   same height, and it moves every second while the page is open. */
.tl-now {
  position: absolute;
  top: -3px; bottom: -3px;
  width: 2px;
  background: #ff5b4a;
  box-shadow: 0 0 0 3px rgba(255, 91, 74, 0.18);
  transition: left 1s linear;
}

.tl-axis {
  display: flex;
  justify-content: space-between;
  font-family: var(--mono);
  font-size: 10.5px;
  color: var(--ink-3);
  margin-top: 6px;
}
.tl-legend {
  display: flex;
  align-items: center;
  gap: 6px;
  flex-wrap: wrap;
  font-family: var(--nav);
  font-size: 10.5px;
  color: var(--ink-3);
}
.tl-legend i { width: 10px; height: 10px; border-radius: 3px; display: inline-block; }
.tl-legend span { margin-right: 4px; }
.tl-note { margin: 8px 0 0; font-family: var(--nav); font-size: 12px; color: var(--ink-3); }

/* ---- numbers and the roster -------------------------------------------- */

.big-n {
  font-family: var(--display);
  font-size: clamp(28px, 9vw, 38px);
  font-weight: 700;
  letter-spacing: -0.02em;
  margin: 4px 0 2px;
}

.upnext { display: grid; gap: 8px; }
.upnext-i {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: 2px 10px;
  padding: 10px 12px;
  border: 1px solid var(--line);
  border-radius: 10px;
}
.upnext-d { font-family: var(--nav); font-size: 12.5px; font-weight: 600; }
.upnext-t { font-family: var(--mono); font-size: 12.5px; color: var(--ink-2); }
.upnext-n { grid-column: 1 / -1; font-size: 12px; color: var(--ink-3); }

.pill.st-approved  { background: rgba(120, 200, 140, 0.16); color: #79c88c; }
.pill.st-pending   { background: rgba(232, 184, 59, 0.16); color: #e8b83b; }
.pill.st-declined,
.pill.st-cancelled { background: rgba(255, 91, 74, 0.14); color: #ff8878; }

/* ---- the signature pad ------------------------------------------------- */

.sigwrap { margin-top: 4px; }
.sigpad {
  width: 100%;
  height: 150px;
  margin-top: 8px;
  border: 1px dashed var(--line);
  border-radius: 10px;
  background: rgba(255, 255, 255, 0.03);
  /* The finger draws on it; it must not scroll the page while doing so. */
  touch-action: none;
  cursor: crosshair;
  display: block;
}

/* ---- once there is room ------------------------------------------------ */

@media (min-width: 900px) {
  .shift-top { grid-template-columns: minmax(280px, 360px) 1fr; gap: 16px; }
  .clock-acts { grid-template-columns: 1fr 1fr; }
  .clock-acts .btn { padding: 11px 16px; font-size: 14px; }
  .sigpad { height: 190px; }
}

/* ---- one page, sections stacked ---------------------------------------- */

.sec-h {
  font-family: var(--display);
  font-size: clamp(19px, 5.2vw, 24px);
  font-weight: 700;
  letter-spacing: -0.02em;
  margin: 26px 0 12px;
  scroll-margin-top: 76px;
}
.sec-h:first-of-type { margin-top: 4px; }

/* The page is long by design, so it carries its own index. Sticky, because
   halfway down a checklist is exactly where you want it. */
.jump {
  position: sticky;
  top: 0;
  z-index: 5;
  display: flex;
  gap: 6px;
  overflow-x: auto;
  scrollbar-width: none;
  padding: 8px 0;
  margin: 0 calc(var(--pad, 20px) * -1) 4px;
  padding-inline: var(--pad, 20px);
  background: linear-gradient(var(--paper) 68%, transparent);
}
.jump::-webkit-scrollbar { display: none; }
.jump a {
  flex: 0 0 auto;
  font-family: var(--nav);
  font-size: 12.5px;
  color: var(--ink-2);
  text-decoration: none;
  border: 1px solid var(--line);
  border-radius: 999px;
  padding: 7px 14px;
}
.jump a:hover { color: var(--ink); border-color: rgba(255, 255, 255, 0.3); }

/* ---- what is owed today ------------------------------------------------ */

.duegrid { display: grid; gap: 8px; grid-template-columns: 1fr; margin-bottom: 12px; }
.due {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  padding: 12px 14px;
  border: 1px solid var(--line);
  border-left: 3px solid #e8b83b;
  border-radius: 10px;
}
.due-k { font-family: var(--nav); font-size: 13.5px; font-weight: 600; }
.due-v {
  font-family: var(--nav);
  font-size: 11px;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: #e8b83b;
}
.due.is-done { border-left-color: #79c88c; }
.due.is-done .due-v { color: #79c88c; }
.due.is-bad { border-left-color: #ff5b4a; }
.due.is-bad .due-v { color: #ff8878; }
.due-note { display: block; font-size: 11.5px; color: var(--ink-3); margin-top: 3px; }

/* ---- the checklists ---------------------------------------------------- */

.formcard { margin-top: 12px; }
.insp-form { margin-top: 14px; }
.checklist { display: grid; gap: 6px; margin: 6px 0 4px; }

/* One row per item: the thing being checked, and three ways to answer it.
   The row is the target, not the radio — a 13-point walkaround done in gloves
   is not the place for a 16px hit area. */
.ck {
  display: grid;
  grid-template-columns: 1fr;
  gap: 6px;
  padding: 10px 12px;
  border: 1px solid var(--line);
  border-radius: 10px;
}
.ck-l { font-family: var(--nav); font-size: 13.5px; }
.ck-opts { display: grid; grid-template-columns: repeat(3, 1fr); gap: 6px; }
.ck-o {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 9px 4px;
  border: 1px solid var(--line);
  border-radius: 8px;
  font-family: var(--nav);
  font-size: 12px;
  color: var(--ink-3);
  cursor: pointer;
  user-select: none;
}
.ck-o input { position: absolute; opacity: 0; pointer-events: none; }
.ck-o:has(input:checked) { color: var(--paper); background: var(--ink); border-color: var(--ink); }
.ck-fail:has(input:checked) { background: #ff5b4a; border-color: #ff5b4a; color: #fff; }
.ck-na:has(input:checked) { background: var(--line); border-color: var(--line); color: var(--ink-2); }
.ck:has(.ck-fail input:checked) { border-color: rgba(255, 91, 74, 0.5); }

@media (min-width: 720px) {
  .ck { grid-template-columns: 1fr auto; align-items: center; }
  .ck-opts { grid-template-columns: repeat(3, 84px); }
  .duegrid { grid-template-columns: repeat(auto-fit, minmax(190px, 1fr)); }
}

/* [hidden] is a UA style of display:none, which any class that sets display
   beats on specificity. .pform is display:grid, so a hidden form was showing.
   Stated here so the attribute means what it says wherever it is used. */
[hidden] { display: none !important; }

/* ==========================================================================
   The portal's own voice.

   The public site is set in Archivo, which is doing a job there that a UI face
   should not: condensed, loud, built for a headline the size of a wall. A tool
   somebody holds in gloves at six in the morning wants the opposite — high
   x-height, open apertures, unremarkable at 13px, and numerals that line up in
   a column. Instrument Sans does that; the site keeps its own face.
   ========================================================================== */

/* One face, everywhere in here. portal.css is loaded by the portal and by
   nothing else, so redefining the three family variables at the root covers
   the sign-in page and the app together — headings, eyebrows, table headers,
   pills and form controls — without touching the public site, which keeps
   Archivo and Plex.

   --mono goes too. It was buying alignment in timestamps and table headers;
   font-variant-numeric below buys the same thing from a proportional face, and
   a portal that speaks in one voice is worth more than a monospaced eyebrow. */
:root {
  --display: "Instrument Sans", -apple-system, BlinkMacSystemFont, system-ui, sans-serif;
  --nav:     "Instrument Sans", -apple-system, BlinkMacSystemFont, system-ui, sans-serif;
  --mono:    "Instrument Sans", -apple-system, BlinkMacSystemFont, system-ui, sans-serif;
  --ui:      "Instrument Sans", -apple-system, BlinkMacSystemFont, system-ui, sans-serif;
}

body,
input, select, textarea, button {
  font-family: var(--ui);
}

/* Anything that was monospaced was monospaced to line up. Keep that. */
.ptable th, .ptable td, .tl-axis, .pill, .hero-k, .tile-k, .stat-l,
.field-l, .phead, .pnav-h, .ptop-k { font-variant-numeric: tabular-nums; }

/* Anything that is a quantity gets tabular figures, so a clock ticking from
   0:09 to 0:10 does not shuffle the digits beside it. */
.tile-n, .big-n, .stat-n, .clock-since, .tl-axis, .ptable td { font-variant-numeric: tabular-nums; }

/* ---- glass -------------------------------------------------------------
   A pane lit from above rather than a flat panel: a top-edge highlight, a
   gradient that falls away, and a blur that lets the page beneath show as
   colour instead of detail. On a dark ground the highlight is what reads as
   glass — without it this is just a grey box. */

.glass {
  background:
    linear-gradient(180deg, rgba(255, 255, 255, 0.055), rgba(255, 255, 255, 0.022));
  backdrop-filter: blur(20px) saturate(160%);
  -webkit-backdrop-filter: blur(20px) saturate(160%);
  border: 1px solid rgba(255, 255, 255, 0.09);
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.09),
    0 10px 30px rgba(0, 0, 0, 0.35);
}

/* ---- the greeting ------------------------------------------------------ */

.hero { padding: 4px 0 18px; }
.hero-k {
  font-size: 11.5px;
  font-weight: 500;
  letter-spacing: 0.13em;
  text-transform: uppercase;
  color: var(--ink-3);
  margin: 0 0 10px;
}
.hero-h {
  font-size: clamp(34px, 10vw, 52px);
  font-weight: 600;
  letter-spacing: -0.035em;
  line-height: 1.02;
  margin: 0;
}
.hero-s {
  font-size: 15px;
  line-height: 1.5;
  color: var(--ink-2);
  margin: 10px 0 0;
  max-width: 46ch;
}

/* Two things, side by side, big enough to hit without looking. These are the
   reason somebody opened the app; everything else is consequence. */
.hero-acts {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 10px;
  margin-top: 20px;
}
.act {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 9px;
  padding: 17px 14px;
  border-radius: 15px;
  border: 1px solid rgba(255, 255, 255, 0.12);
  background: linear-gradient(180deg, rgba(255, 255, 255, 0.075), rgba(255, 255, 255, 0.03));
  backdrop-filter: blur(18px) saturate(160%);
  -webkit-backdrop-filter: blur(18px) saturate(160%);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.10);
  color: var(--ink);
  font-size: 14.5px;
  font-weight: 550;
  cursor: pointer;
  transition: transform 0.18s cubic-bezier(0.22, 1, 0.36, 1), background 0.18s ease;
}
.act:hover { background: linear-gradient(180deg, rgba(255,255,255,0.11), rgba(255,255,255,0.05)); }
.act:active { transform: scale(0.975); }
.act svg { width: 19px; height: 19px; fill: none; stroke: currentColor; stroke-width: 1.7; flex: 0 0 auto; }

/* ---- the tiles --------------------------------------------------------- */

.tiles { display: grid; grid-template-columns: repeat(3, 1fr); gap: 9px; }
.tile { padding: 14px 12px; border-radius: 15px; }
.tile-k {
  margin: 0 0 6px;
  font-size: 10.5px;
  font-weight: 500;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  color: var(--ink-3);
  line-height: 1.3;
}
.tile-n {
  margin: 0;
  font-size: clamp(24px, 7vw, 30px);
  font-weight: 600;
  letter-spacing: -0.03em;
}
.tile-n.amber { color: #e8b83b; }
.tile-n.good { color: #79c88c; }

/* Headings lose Archivo's condensed shout and pick up the UI face, because a
   section label is furniture, not a headline. */
.sec-h { font-family: inherit; font-weight: 600; letter-spacing: -0.028em; }
.pcard-clock .clock-since { font-weight: 600; letter-spacing: -0.03em; }
.hero-h, .tile-n, .big-n { font-family: inherit; }

@media (min-width: 900px) {
  .hero-acts { max-width: 520px; }
}

/* Somebody who has asked for less movement gets less movement: the reveal
   below is an entrance, not information, so it simply is not played. */
@media (prefers-reduced-motion: reduce) {
  .rise { opacity: 1 !important; transform: none !important; }
}

/* ---- the roster screen -------------------------------------------------
   Two jobs on one page: answer what is waiting, then put people on days.
   Both are lists of rows, so both are built the same way — a name, the detail
   under it, and the decision on the right where the thumb already is. */

.reqlist { display: grid; gap: 8px; }
.req {
  display: grid;
  gap: 10px;
  padding: 13px 14px;
  border: 1px solid var(--line);
  border-left: 3px solid #e8b83b;
  border-radius: 12px;
}
.req-who { display: grid; gap: 2px; min-width: 0; }
.req-n { font-size: 14.5px; font-weight: 600; }
.req-d { font-size: 12.5px; color: var(--ink-2); }
.req-note { font-size: 12px; color: var(--ink-3); }
.req-acts { display: grid; grid-template-columns: 1fr 1fr; gap: 8px; }

.rosterdays { display: grid; gap: 14px; }
.rday-h {
  margin: 0 0 6px;
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--ink-3);
}
.rrow {
  display: grid;
  grid-template-columns: 1fr auto;
  gap: 3px 10px;
  align-items: center;
  padding: 11px 12px;
  border: 1px solid var(--line);
  border-radius: 11px;
}
.rrow + .rrow { margin-top: 6px; }
.rrow-n { font-size: 14px; font-weight: 600; }
.rrow-t { font-size: 12.5px; color: var(--ink-2); grid-column: 1; }
.rrow-x { font-size: 12px; color: var(--ink-3); grid-column: 1; }
.rrow button { grid-row: 1 / span 3; grid-column: 2; }

/* Wide enough to put the decision beside the request rather than under it. */
@media (min-width: 760px) {
  .req { grid-template-columns: 1fr auto; align-items: center; }
  .req-acts { grid-template-columns: auto auto; }
  .rrow { grid-template-columns: 1.4fr 1fr 1.6fr auto; }
  .rrow-t, .rrow-x { grid-column: auto; }
  /* The narrow rule pins this to column 2 so it can sit beside a stacked
     name; here the row is four columns and it belongs at the end. Resetting
     the row without the column left Remove wedged between the name and the
     time. */
  .rrow button { grid-row: 1; grid-column: 4; }
}

/* ---- the signature, given room ----------------------------------------
   It used to share a row with two text fields, which left a strip too narrow
   to sign in on the tablet these are filled in on. Full width, and tall
   enough that a signature is a signature rather than an initial. */

.sigwrap.wide { grid-column: 1 / -1; }
.sigpad.tall { height: 200px; }
@media (min-width: 720px) { .sigpad.tall { height: 260px; } }

/* ---- photographs ------------------------------------------------------- */

.shots { display: grid; grid-template-columns: repeat(4, 1fr); gap: 8px; margin-top: 10px; }
.shot { position: relative; aspect-ratio: 1; border-radius: 10px; overflow: hidden; border: 1px solid var(--line); }
.shot img { width: 100%; height: 100%; object-fit: cover; display: block; }
.shot button {
  position: absolute; top: 5px; right: 5px;
  width: 24px; height: 24px; padding: 0;
  border: 0; border-radius: 50%;
  background: rgba(10, 11, 13, 0.78);
  backdrop-filter: blur(6px);
  color: var(--ink);
  font-size: 15px; line-height: 1;
  cursor: pointer;
}
.shots:empty { display: none; }

/* A label styled as a button is still a label: it opens the file picker on tap
   without any script, which is one less thing to fail on a bad connection. */
label.btn { display: inline-flex; align-items: center; cursor: pointer; }
