:root {
  /* Brand palette, matching mcray-roofing-site/css/styles.css */
  --maroon: #870412;
  --maroon-dark: #5C0210;
  --charcoal: #1E1517;
  --slate: #4A3C3E;
  --gray: #99A1AF;
  --gray-light: #f6f2f1;
  --off-white: #FAF9F7;
  --white: #ffffff;
  --maroon-gradient: linear-gradient(135deg, var(--maroon) 0%, var(--maroon-dark) 100%);
  --accent-red: #D6453D;
  --accent-red-dark: #85020F;

  /* Same "gold" as the main site's .hero-btn-gold -- the copper roof-tile gradient,
     upgraded to a multi-stop polished-metal sheen (a bright highlight band
     between two darker brass tones) rather than a flat two-color gradient. */
  --roof-3: #DA984F;
  --roof-4: #FBA86B;
  --gold-gradient: linear-gradient(120deg, #B9803A 0%, #DA984F 30%, #EAC087 50%, #DA984F 70%, #B9803A 100%);

  /* Refined "floating" chrome shadows -- kept separate from the data
     tables' plain --gray-light hairlines, which stay untouched so rows
     stay easy to scan. --hairline is a softer border for cards/panels. */
  --hairline: rgba(30, 21, 23, 0.07);
  --shadow-card: 0 1px 2px rgba(30, 21, 23, 0.04), 0 10px 28px rgba(30, 21, 23, 0.07);
  --shadow-card-hover: 0 2px 6px rgba(30, 21, 23, 0.06), 0 16px 40px rgba(30, 21, 23, 0.11);
  --shadow-float: 0 16px 40px rgba(30, 21, 23, 0.2);
}

* { box-sizing: border-box; }

html[data-ui-density="compact"] { zoom: 0.85; }
html[data-ui-density="comfortable"] { zoom: 1.15; }

body {
  margin: 0;
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
  background: radial-gradient(120% 120% at 50% -10%, #ffffff 0%, var(--off-white) 45%);
  color: var(--charcoal);
  min-height: 100vh;
  min-height: 100dvh;
}

.wrap {
  max-width: var(--wrap-max-width, 480px);
  margin: 0 auto;
  padding: 24px 20px 40px;
}

.top-banner {
  position: relative;
  width: 100%;
  background: var(--maroon-gradient);
  padding: 10px 20px;
  box-shadow: 0 4px 20px rgba(30, 21, 23, 0.18);
}

.top-banner::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  height: 2px;
  background: var(--gold-gradient);
  opacity: 0.85;
}

.banner-inner {
  position: relative;
  max-width: 480px;
  margin: 0 auto;
  display: flex;
  align-items: center;
  justify-content: center;
  flex-wrap: wrap;
  gap: 8px;
  color: var(--white);
  font-size: 0.85rem;
  text-align: center;
}

.banner-inner label {
  display: none;
}

.top-banner .banner-inner select,
.top-banner .banner-inner input {
  width: auto;
  min-width: 0;
  flex: 1 1 110px;
  padding: 0 10px;
  font-size: 0.85rem;
  margin-bottom: 0;
  border-radius: 8px;
}

.top-banner .banner-inner select,
.top-banner .banner-inner input,
.top-banner .banner-inner button {
  height: 34px;
  line-height: 34px;
  box-sizing: border-box;
}

.top-banner .banner-inner button {
  flex: 0 0 auto;
  padding: 0 14px;
  font-size: 0.85rem;
}

.banner-inner .message {
  margin: 0;
  text-align: center;
  min-height: 0;
  flex-basis: 100%;
}

.banner-inner strong {
  color: var(--white);
}

.banner-inner a {
  color: var(--white);
  font-weight: 600;
  text-decoration: underline;
}

.top-banner.centered {
  min-height: 100vh;
  min-height: 100dvh;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 24px 20px;
}

.login-box {
  position: relative;
  flex-direction: column;
  align-items: stretch;
  gap: 14px;
  background: var(--white);
  color: var(--charcoal);
  border-radius: 12px;
  padding: 40px 32px 36px;
  max-width: 400px;
  width: 100%;
  box-shadow: var(--shadow-float);
  animation: card-settle 0.35s cubic-bezier(.2, .8, .2, 1);
}

@keyframes card-settle {
  from { opacity: 0; transform: translateY(6px) scale(0.99); }
  to { opacity: 1; transform: translateY(0) scale(1); }
}

.login-box::before {
  content: "";
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  height: 3px;
  background: var(--gold-gradient);
  border-radius: 12px 12px 0 0;
}

.login-logo {
  display: block;
  height: 54px;
  margin: 0 auto 4px;
}

.login-title {
  font-size: 0.8rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.09em;
  color: var(--maroon);
  text-align: center;
  margin: -4px 0 4px;
}

.top-banner.centered .login-box select,
.top-banner.centered .login-box input,
.top-banner.centered .login-box button,
.top-banner.centered .login-box .custom-select-trigger {
  max-width: none;
  box-sizing: border-box;
}

.top-banner.centered .login-box select,
.top-banner.centered .login-box input[type="text"] {
  height: 26px;
  line-height: 26px;
  padding: 0 10px;
  font-size: 0.85rem;
}

/* The name dropdown is sized to pair with the PIN digit boxes below (same
   padding, same bespoke finish), not the compact 26px rule above.
   Padding-driven sizing, not a forced height/line-height -- same
   technique the rest of the site's inputs already use. */
.top-banner.centered .login-box .custom-select-trigger {
  padding: 10px 14px;
  font-size: 0.95rem;
}

/* 4-digit segmented PIN entry (see pin-box.js) -- one real <input> per
   digit instead of a single text field, so there's no single box whose
   sizing can fight with the browser the way the old one did. Each digit's
   font-size (20px, set below) must stay at or above 16px on purpose:
   anything smaller makes iOS Safari zoom the whole page in on focus. */
.pin-box {
  display: flex;
  gap: 8px;
  justify-content: center;
  margin-bottom: 16px;
  min-width: 0;
  width: 100%;
  box-sizing: border-box;
}

/* Scoped under the full login-box ancestor chain (not just `.pin-digit`
   alone) so this reliably outranks the generic
   `input[type="password"] { width:100%; padding:14px; ... }` rule --
   that rule's type+attribute selector gives it more specificity than a
   single class would on its own. */
.top-banner.centered .login-box .pin-digit {
  flex: 1 1 0;
  width: auto;
  min-width: 0;
  max-width: 46px;
  height: auto;
  padding: 12px 0;
  margin-bottom: 0;
  font-size: 24px;
  font-weight: 600;
  line-height: normal;
  text-align: center;
  font-variant-numeric: tabular-nums;
  transition: border-color 0.15s ease, box-shadow 0.15s ease, transform 0.12s ease, background 0.15s ease, color 0.15s ease;
}

/* Shared bespoke finish for each PIN digit box and the name dropdown -- a
   brass-tinted hairline and a carved inset shadow instead of the flat
   gray-bordered look every other site's inputs use, so these read as
   purpose-built for McRay rather than default browser chrome. */
.top-banner.centered .login-box .pin-digit,
.top-banner.centered .login-box .custom-select-trigger {
  background: var(--off-white);
  border: 1px solid rgba(218, 152, 79, 0.4);
  box-shadow: inset 0 1px 3px rgba(30, 21, 23, 0.08);
}

.top-banner.centered .login-box .pin-digit:hover {
  border-color: rgba(135, 4, 18, 0.35);
}

/* A digit that's actually been typed reads as "entered" -- maroon text and
   a warmer filled border -- rather than looking identical to an empty box. */
.top-banner.centered .login-box .pin-digit.pin-digit-filled {
  background: var(--white);
  border-color: var(--maroon);
  color: var(--maroon);
}

.top-banner.centered .login-box .pin-digit:focus,
.top-banner.centered .login-box .custom-select-trigger:focus,
.top-banner.centered .login-box .custom-select-trigger.open {
  border-color: var(--maroon);
  box-shadow: inset 0 1px 3px rgba(30, 21, 23, 0.08), 0 0 0 3px rgba(135, 4, 18, 0.14);
}

.top-banner.centered .login-box .pin-digit:focus {
  transform: translateY(-2px);
}

.top-banner.centered .login-box .pin-digit:active {
  transform: translateY(0) scale(0.96);
}

/* Per-digit "just typed" bounce. */
@keyframes pin-pop {
  0% { transform: scale(1); }
  40% { transform: scale(1.16); }
  100% { transform: scale(1); }
}

.top-banner.centered .login-box .pin-digit.pin-digit-pop {
  animation: pin-pop 0.22s cubic-bezier(.34, 1.56, .64, 1);
}

/* Wrong-PIN feedback: a quick horizontal shake plus a momentary red-tinted
   border on every digit, triggered by PinBox.shake() in pin-box.js. */
@keyframes pin-shake {
  10%, 90% { transform: translateX(-1px); }
  20%, 80% { transform: translateX(3px); }
  30%, 50%, 70% { transform: translateX(-6px); }
  40%, 60% { transform: translateX(6px); }
}

.pin-box.pin-box-shake {
  animation: pin-shake 0.45s cubic-bezier(.36, .07, .19, .97);
}

.top-banner.centered .login-box .pin-box.pin-box-shake .pin-digit {
  border-color: var(--accent-red-dark);
}

/* Correct-PIN feedback: a soft gold glow washing across the digits,
   triggered by PinBox.success() before the sign-in screen hands off to the
   signed-in view. */
@keyframes pin-success-glow {
  0% { box-shadow: inset 0 1px 3px rgba(30, 21, 23, 0.08), 0 0 0 0 rgba(218, 152, 79, 0.55); }
  45% { box-shadow: inset 0 1px 3px rgba(30, 21, 23, 0.08), 0 0 0 5px rgba(218, 152, 79, 0.28); }
  100% { box-shadow: inset 0 1px 3px rgba(30, 21, 23, 0.08), 0 0 0 0 rgba(218, 152, 79, 0); }
}

.top-banner.centered .login-box .pin-box.pin-box-success .pin-digit {
  border-color: var(--roof-4);
  animation: pin-success-glow 0.7s ease;
}

.top-banner.centered .login-box button {
  height: auto;
  line-height: 1.3;
  padding: 12px 14px;
  font-size: 1.1rem;
}

.login-box .message {
  color: var(--accent-red-dark);
}

#signInFields,
#resetPinFields {
  display: flex;
  flex-direction: column;
  gap: 10px;
  min-width: 0;
  width: 100%;
  box-sizing: border-box;
}

.security-question {
  font-size: 0.9rem;
  color: var(--slate);
  text-align: center;
}

.login-box a {
  color: var(--maroon);
  font-size: 0.85rem;
  font-weight: 600;
  text-decoration: none;
}

header {
  text-align: center;
  margin-bottom: 28px;
}

header .logo-img {
  height: 44px;
  margin-bottom: 6px;
}

header h1 {
  margin: 0;
  font-weight: 700;
  font-size: 1.5rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--charcoal);
}

header::after {
  content: "";
  display: block;
  width: 48px;
  height: 2px;
  margin: 14px auto 0;
  background: var(--gold-gradient);
  border-radius: 2px;
}

.top-banner .banner-inner .settings-btn {
  display: flex;
  align-items: center;
  justify-content: center;
  flex: none;
  width: 30px;
  height: 30px;
  padding: 0;
  border-radius: 50%;
  background: rgba(255, 255, 255, 0.15);
  border: 1px solid rgba(255, 255, 255, 0.35);
  color: var(--white);
  font-size: 1.35rem;
  line-height: 1;
  box-shadow: inset 0 1px 1px rgba(255, 255, 255, 0.3), inset 0 -1px 2px rgba(0, 0, 0, 0.15);
  transition: transform 0.3s ease, background 0.15s ease;
}

.top-banner .banner-inner .settings-btn:hover {
  background: rgba(255, 255, 255, 0.3);
  transform: rotate(45deg);
}

.settings-panel {
  display: none;
  position: absolute;
  top: calc(100% + 10px);
  right: 0;
  width: 250px;
  background: var(--white);
  border: 1px solid var(--hairline);
  border-radius: 10px;
  box-shadow: var(--shadow-float);
  padding: 16px;
  text-align: left;
  z-index: 25;
}

.settings-panel.open {
  display: block;
  animation: settings-pop 0.15s ease;
}

@keyframes settings-pop {
  from { opacity: 0; transform: translateY(-4px) scale(0.98); }
  to { opacity: 1; transform: translateY(0) scale(1); }
}

.settings-panel-title {
  font-size: 0.75rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--maroon);
  margin-bottom: 14px;
}

.confirm-panel {
  width: 230px;
}

/* Ported from the admin site's modal (Add Employee) -- same visual
   pattern reused here for the "Request Edit"/"Request Missing Punch"
   forms, so a future shared-CSS pass could de-duplicate this. */
.modal-overlay {
  position: fixed;
  inset: 0;
  background: rgba(30, 21, 23, 0.5);
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 20px;
  z-index: 200;
}

.modal-card {
  background: var(--white);
  border-radius: 14px;
  padding: 28px 24px;
  max-width: 360px;
  width: 100%;
  max-height: 90vh;
  overflow-y: auto;
  box-shadow: var(--shadow-float);
}

/* Wider/taller than the standard modal-card -- a map needs real screen
   space to be usable, unlike the small forms every other modal holds. */
.job-map-card {
  max-width: 640px;
  height: 90vh;
  display: flex;
  flex-direction: column;
}

#jobMapContainer {
  flex: 1;
  min-height: 300px;
  border-radius: 10px;
  border: 1px solid var(--hairline);
  overflow: hidden;
}

.job-map-search-input {
  margin-bottom: 10px;
  flex: none;
}

.job-picker-row {
  display: flex;
  gap: 8px;
  align-items: stretch;
}

.job-picker-row .custom-select {
  flex: 1;
  min-width: 0;
}

.job-picker-row .custom-select-trigger {
  height: 100%;
  box-sizing: border-box;
}

.job-map-btn {
  flex: none;
  width: 44px;
  font-size: 1.2rem;
  padding: 0;
  display: flex;
  align-items: center;
  justify-content: center;
}

#jobRefreshBtn.spinning svg {
  animation: job-refresh-spin 0.8s linear infinite;
}

@keyframes job-refresh-spin {
  from { transform: rotate(0deg); }
  to { transform: rotate(360deg); }
}

/* Leaflet popup content -- job name + a real select button, styled to
   match the app's own buttons rather than Leaflet's plain default look. */
.job-map-popup-name {
  font-weight: 600;
  margin-bottom: 8px;
  color: var(--charcoal);
}

/* Custom SVG marker pin -- Leaflet's default .leaflet-div-icon gives every
   div-icon a white box background/border; explicitly clearing it here in
   case that default ever leaks through, since our className already
   replaces (not extends) leaflet-div-icon in normal operation. */
.job-map-pin {
  background: none;
  border: none;
}

.modal-title {
  font-size: 1.1rem;
  font-weight: 700;
  color: var(--charcoal);
  text-align: center;
  margin-bottom: 18px;
}

.confirm-text {
  margin: 0 0 14px;
  font-size: 0.85rem;
  line-height: 1.4;
  color: var(--slate);
}

.confirm-actions {
  display: flex;
  gap: 8px;
}

.confirm-actions .cancel-btn {
  background: var(--gray-light);
  color: var(--slate);
}

.settings-group {
  margin-bottom: 14px;
}

.settings-group:last-child {
  margin-bottom: 0;
}

.settings-link-btn {
  display: block;
  text-align: center;
  padding: 8px 0;
  border-radius: 6px;
  background: var(--gray-light);
  color: var(--maroon);
  font-size: 0.85rem;
  font-weight: 600;
  text-decoration: none;
  border: none;
  width: 100%;
  cursor: pointer;
  transition: background 0.15s ease;
}

.settings-link-btn:hover {
  background: var(--hairline);
}

.settings-label {
  display: flex;
  justify-content: space-between;
  font-size: 0.8rem;
  color: var(--slate);
  margin-bottom: 8px;
}

.settings-readout {
  font-weight: 600;
  color: var(--maroon);
}

.segmented-control {
  display: flex;
  background: var(--gray-light);
  border-radius: 8px;
  padding: 3px;
  gap: 2px;
}

.segmented-control .segmented-option {
  flex: 1;
  padding: 6px 4px;
  font-size: 0.75rem;
  font-weight: 500;
  border-radius: 6px;
  background: transparent;
  color: var(--slate);
  box-shadow: none;
}

.segmented-control .segmented-option.active {
  background: var(--white);
  color: var(--maroon);
  font-weight: 600;
  box-shadow: 0 1px 3px rgba(30, 21, 23, 0.12);
}

.settings-panel input[type="range"] {
  width: 100%;
  margin: 0;
  accent-color: var(--maroon);
}

.settings-panel input[type="range"]::-webkit-slider-thumb {
  background: var(--gold-gradient);
}

.settings-panel input[type="range"]::-moz-range-thumb {
  background: var(--gold-gradient);
  border: none;
}

nav.tabs {
  display: flex;
  gap: 8px;
  margin-bottom: 24px;
}

nav.tabs a {
  flex: 1;
  text-align: center;
  padding: 10px 0;
  border-radius: 8px;
  text-decoration: none;
  color: var(--slate);
  background: var(--gray-light);
  font-size: 0.9rem;
  font-weight: 600;
  letter-spacing: 0.01em;
  transition: background 0.15s ease, color 0.15s ease, transform 0.1s ease;
}

nav.tabs a:active {
  transform: scale(0.97);
}

nav.tabs a.active {
  background: var(--maroon-gradient);
  color: var(--white);
  font-weight: 600;
}

.card {
  position: relative;
  background: var(--white);
  border: 1px solid var(--hairline);
  border-radius: 10px;
  padding: 22px;
  margin-bottom: 16px;
  box-shadow: var(--shadow-card);
  transition: box-shadow 0.2s ease;
}

.card::before {
  content: "";
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  height: 3px;
  background: var(--gold-gradient);
  border-radius: 10px 10px 0 0;
  opacity: 0.9;
}

@media (hover: hover) {
  .card:hover {
    box-shadow: var(--shadow-card-hover);
  }
}

label {
  display: block;
  font-size: 0.85rem;
  color: var(--slate);
  margin-bottom: 6px;
}

select, input[type="password"], input[type="tel"], input[type="text"], input[type="date"], input[type="datetime-local"], textarea, .custom-select-trigger {
  width: 100%;
  padding: 14px;
  font-size: 1.1rem;
  border-radius: 8px;
  border: 1px solid var(--gray);
  background: var(--off-white);
  color: var(--charcoal);
  margin-bottom: 16px;
  -webkit-appearance: none;
  transition: border-color 0.15s ease, box-shadow 0.15s ease, transform 0.1s ease;
}

textarea {
  font-family: inherit;
  resize: vertical;
}

select:focus, input:focus, .custom-select-trigger:focus, .custom-select-trigger.open {
  outline: none;
  border-color: var(--maroon);
  box-shadow: 0 0 0 3px rgba(135, 4, 18, 0.14);
}

.custom-select-trigger:active {
  transform: scale(0.965);
  transition-duration: 0.05s;
}

/* Fully custom dropdown, replacing the browser's native <select> popup --
   the real <select> stays in the DOM (hidden) as the data source; see
   custom-select.js. */
.custom-select {
  position: relative;
  cursor: pointer;
}

.custom-select-source {
  position: absolute;
  opacity: 0;
  pointer-events: none;
  width: 1px;
  height: 1px;
}

.custom-select-trigger {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  cursor: pointer;
}

.custom-select-trigger:hover {
  border-color: var(--slate);
}

.custom-select-trigger.disabled {
  opacity: 0.5;
  cursor: default;
  pointer-events: none;
}

.custom-select-label {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* Placeholder state (e.g. "[Select]") -- lighter/greyed so it visibly reads
   as "nothing chosen yet" instead of looking like a real selected value. */
.custom-select-trigger.placeholder .custom-select-label {
  color: var(--gray);
}

.custom-select-caret {
  flex: none;
  width: 0;
  height: 0;
  border-left: 5px solid transparent;
  border-right: 5px solid transparent;
  border-top: 6px solid var(--slate);
  transition: transform 0.2s ease;
}

.custom-select-trigger.open .custom-select-caret {
  transform: rotate(180deg);
}

.custom-select-menu {
  display: none;
  position: absolute;
  top: calc(100% + 6px);
  left: 0;
  right: 0;
  max-height: 260px;
  overflow-y: auto;
  background: var(--white);
  border: 1px solid var(--hairline);
  border-radius: 10px;
  box-shadow: var(--shadow-float);
  padding: 6px;
  z-index: 30;
}

.custom-select-menu.open {
  display: block;
  animation: settings-pop 0.15s ease;
}

.custom-select-option {
  padding: 10px 12px;
  border-radius: 6px;
  font-size: 0.95rem;
  color: var(--charcoal);
  cursor: pointer;
  transform: scale(1);
  transition: background 0.08s ease, transform 0.06s ease;
}

.custom-select-option.highlighted,
.custom-select-option:hover {
  background: var(--gray-light);
}

/* Pressed feedback -- fires on mousedown (before the option-list rebuild
   that click triggers), so it reads as a real tactile "press" rather than
   the item just silently vanishing when the menu closes. */
.custom-select-option:active {
  background: rgba(135, 4, 18, 0.14);
  transform: scale(0.97);
  transition-duration: 0.04s;
}

.custom-select-option.selected {
  color: var(--maroon);
  font-weight: 600;
}

.custom-select-option.selected::after {
  content: "\2713";
  float: right;
}

.custom-select-option.hidden {
  display: none;
}

.custom-select-search {
  padding: 4px 4px 8px;
  margin-bottom: 6px;
  border-bottom: 1px solid var(--gray-light);
}

.custom-select-search-input {
  width: 100%;
  padding: 9px 10px;
  font-size: 0.9rem;
  border: 1px solid var(--gray);
  border-radius: 8px;
  background: var(--off-white);
  color: var(--charcoal);
  -webkit-appearance: none;
  transition: border-color 0.15s ease, box-shadow 0.15s ease;
}

.custom-select-search-input:focus {
  outline: none;
  border-color: var(--maroon);
  box-shadow: 0 0 0 3px rgba(135, 4, 18, 0.14);
}

.custom-select-empty {
  display: none;
  padding: 10px 12px;
  font-size: 0.85rem;
  font-style: italic;
  color: var(--gray);
  text-align: center;
}

.status {
  text-align: center;
  padding: 16px;
  border-radius: 8px;
  margin-bottom: 16px;
  font-size: 1.05rem;
  font-weight: 700;
  letter-spacing: 0.01em;
  transition: background 0.25s ease, color 0.25s ease;
}

.status.in { background: rgba(135, 4, 18, 0.08); color: var(--maroon); }
.status.out { background: var(--gray-light); color: var(--slate); }

/* Skeleton shimmer for the initial "Loading…" state -- hides the text and
   sweeps a soft highlight across the pill instead of showing plain text,
   so the app doesn't flash unstyled copy before the real status resolves.
   The .loading class is only present in the static HTML; the very next
   refreshStatus() call replaces the whole className and clears it. */
.status.loading {
  color: transparent;
  position: relative;
  overflow: hidden;
}

.status.loading::after {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(90deg, var(--gray-light) 0%, rgba(255, 255, 255, 0.9) 50%, var(--gray-light) 100%);
  background-size: 200% 100%;
  animation: status-shimmer 1.3s ease-in-out infinite;
}

@keyframes status-shimmer {
  0% { background-position: 200% 0; }
  100% { background-position: -200% 0; }
}

.btn-row {
  display: flex;
  gap: 12px;
}

button {
  flex: 1;
  padding: 20px 0;
  font-size: 1.15rem;
  font-weight: 600;
  border: none;
  border-radius: 8px;
  cursor: pointer;
  transition: transform 0.12s cubic-bezier(.2, .8, .2, 1), box-shadow 0.15s ease, filter 0.15s ease;
}

button:active:not(:disabled) {
  transform: scale(0.96);
}

button:focus-visible {
  outline: none;
  box-shadow: 0 0 0 3px rgba(135, 4, 18, 0.3);
}

button.in, button.out, button.gold {
  position: relative;
  overflow: hidden;
}

/* Metallic shine sweep -- a diagonal highlight band that slides across the
   button on hover, like light moving across polished metal. */
button.in::after, button.out::after, button.gold::after {
  content: "";
  position: absolute;
  top: 0;
  left: -75%;
  width: 45%;
  height: 100%;
  background: linear-gradient(120deg, transparent, rgba(255, 255, 255, 0.25), transparent);
  transform: skewX(-20deg);
  transition: left 0.5s ease;
  pointer-events: none;
}

@media (hover: hover) {
  button.in:hover:not(:disabled)::after,
  button.out:hover:not(:disabled)::after,
  button.gold:hover:not(:disabled)::after {
    left: 125%;
  }
}

button.in {
  background: var(--maroon-gradient);
  color: var(--white);
  letter-spacing: 0.02em;
  box-shadow: 0 2px 8px rgba(135, 4, 18, 0.25), inset 0 1px 0 rgba(255, 255, 255, 0.14);
}
button.out {
  background: var(--accent-red);
  color: var(--white);
  letter-spacing: 0.02em;
  box-shadow: 0 2px 8px rgba(214, 69, 61, 0.25), inset 0 1px 0 rgba(255, 255, 255, 0.14);
}

@media (hover: hover) {
  button.in:hover:not(:disabled), button.out:hover:not(:disabled) { filter: brightness(1.06); }
}

button.gold {
  background: var(--gold-gradient);
  color: var(--charcoal);
  letter-spacing: 0.02em;
  box-shadow: 0 4px 14px rgba(218, 152, 79, 0.4), inset 0 1px 0 rgba(255, 255, 255, 0.2);
}
button.gold:hover {
  transform: translateY(-2px);
  box-shadow: 0 8px 20px rgba(218, 152, 79, 0.45);
}
button.gold:active:not(:disabled) {
  transform: translateY(0) scale(0.96);
}
button:disabled { opacity: 0.4; cursor: default; }

/* Fired on the just-pressed clock-in/out (or job check-in/out) button after
   a successful punch -- a gold ring that blooms and fades, echoing the PIN
   box's success glow so the "it worked" feeling is consistent app-wide. */
@keyframes btn-success-pulse {
  0% { box-shadow: 0 0 0 0 rgba(218, 152, 79, 0.55); }
  45% { box-shadow: 0 0 0 9px rgba(218, 152, 79, 0.28); }
  100% { box-shadow: 0 0 0 0 rgba(218, 152, 79, 0); }
}

button.btn-success-pulse {
  animation: btn-success-pulse 0.65s ease;
}

.message {
  text-align: center;
  margin-top: 16px;
  font-size: 1rem;
  font-weight: 500;
  min-height: 1.2em;
}

.message.error, .message.ok {
  animation: message-in 0.25s ease;
}

@keyframes message-in {
  from { opacity: 0; transform: translateY(4px); }
  to { opacity: 1; transform: translateY(0); }
}

.message.error { color: var(--accent-red-dark); }
.message.ok { color: var(--maroon); font-weight: 600; }

.message.ok::before {
  content: "\2713";
  display: inline-block;
  margin-right: 5px;
  font-weight: 700;
}

table {
  width: 100%;
  border-collapse: collapse;
  font-size: 0.85rem;
}

th, td {
  text-align: left;
  padding: 10px 8px;
  border-bottom: 1px solid var(--gray-light);
  line-height: 1.4;
}

th {
  color: var(--slate);
  font-weight: 600;
  text-transform: uppercase;
  font-size: 0.68rem;
  letter-spacing: 0.06em;
  background: var(--gray-light);
}

th:first-child { border-radius: 8px 0 0 8px; }
th:last-child { border-radius: 0 8px 8px 0; }

tbody tr {
  transition: background 0.12s ease;
}

tbody tr:nth-child(even) {
  background: rgba(30, 21, 23, 0.02);
}

@media (hover: hover) {
  tbody tr:hover {
    background: rgba(135, 4, 18, 0.05);
  }
}

td {
  font-variant-numeric: tabular-nums;
}

.open-badge {
  display: inline-block;
  padding: 2px 9px;
  border-radius: 999px;
  background: rgba(135, 4, 18, 0.08);
  color: var(--maroon);
  font-weight: 600;
  font-size: 0.72rem;
  letter-spacing: 0.02em;
}

/* Employee-facing edit-request status pills, plus the "My Edit Requests"
   list underneath the punches table -- reuses .weekly-totals' card
   chrome, not a new container style. */
.request-status {
  display: inline-block;
  padding: 2px 9px;
  border-radius: 999px;
  font-weight: 600;
  font-size: 0.72rem;
  letter-spacing: 0.02em;
}

.request-status.pending {
  background: var(--gray-light);
  color: var(--slate);
}

.request-status.approved {
  background: rgba(11, 131, 0, 0.1);
  color: #0b7a00;
}

.request-status.denied {
  background: rgba(214, 69, 61, 0.12);
  color: var(--accent-red-dark);
}

.request-row {
  padding: 10px 0;
  border-bottom: 1px solid var(--gray-light);
  font-size: 0.85rem;
}

.request-row:last-child {
  border-bottom: none;
}

.request-row-top {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 8px;
  margin-bottom: 4px;
}

.request-row-detail {
  color: var(--slate);
  font-size: 0.8rem;
}

.request-row-note {
  color: var(--accent-red-dark);
  font-size: 0.8rem;
  margin-top: 2px;
}

.summary {
  display: flex;
  justify-content: space-between;
  align-items: center;
  font-size: 0.85rem;
  color: var(--slate);
  margin-bottom: 8px;
}

.summary a {
  color: var(--maroon);
  font-weight: 600;
  text-decoration: none;
}

.export-menu-wrap {
  position: relative;
  display: inline-block;
}

.export-menu {
  display: none;
  position: absolute;
  top: calc(100% + 6px);
  right: 0;
  min-width: 110px;
  background: var(--white);
  border: 1px solid var(--hairline);
  border-radius: 10px;
  box-shadow: var(--shadow-float);
  padding: 6px;
  z-index: 30;
}

.export-menu.open {
  display: block;
  animation: settings-pop 0.15s ease;
}

.export-menu-item {
  display: block;
  width: 100%;
  flex: none;
  text-align: left;
  padding: 8px 10px;
  border-radius: 6px;
  background: transparent;
  color: var(--charcoal);
  font-size: 0.8rem;
  font-weight: 500;
}

.export-menu-item:hover {
  background: var(--gray-light);
}

.empty {
  text-align: center;
  color: var(--gray);
  padding: 24px 0;
  font-style: italic;
}

.group {
  background: var(--white);
  border: 1px solid var(--hairline);
  border-radius: 10px;
  padding: 18px 22px 22px;
  margin-bottom: 16px;
  box-shadow: var(--shadow-card);
  transition: box-shadow 0.2s ease;
}

@media (hover: hover) {
  .group:hover {
    box-shadow: var(--shadow-card-hover);
  }
}

.group-header {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  margin-bottom: 10px;
}

.group-header h2 {
  margin: 0;
  font-size: 1.05rem;
  color: var(--charcoal);
}

.group-header .group-total {
  font-weight: 600;
  color: var(--maroon);
  font-size: 0.9rem;
  white-space: nowrap;
  background: rgba(135, 4, 18, 0.06);
  padding: 4px 12px;
  border-radius: 999px;
}

/* ---------- Weekly calendar (one navigable week at a time) ---------- */

.week-nav {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
  margin-bottom: 14px;
  flex-wrap: wrap;
}

.week-nav-btn {
  flex: none;
  width: 34px;
  height: 34px;
  padding: 0;
  border-radius: 50%;
  background: var(--gray-light);
  color: var(--charcoal);
  font-size: 1rem;
  font-weight: 700;
  transition: background 0.15s ease, color 0.15s ease;
}

.week-nav-btn:hover {
  background: var(--maroon-gradient);
  color: var(--white);
}

.week-nav-label {
  font-weight: 600;
  color: var(--charcoal);
  font-size: 0.9rem;
  min-width: 140px;
  text-align: center;
}

.week-calendar {
  margin-bottom: 8px;
}

/* 7 day columns side by side, hour axis on the left (4 AM-10 PM top to
   bottom), day name/date labels below each column. The hour axis and
   each track share the same explicit height and top-align (rather than
   stretching), so the axis labels line up with the alternating hour
   stripes -- one CSS background (repeating-gradient trick), not per-hour
   DOM nodes: an hour is 100%/18 tall, and the gradient's 2-hour repeat
   unit makes them alternate. Punches render as an absolutely-positioned
   bar within the track, positioned/sized by top%/height%. */
.timeline-vgrid {
  display: flex;
  align-items: flex-start;
  gap: 6px;
}

.timeline-hour-axis {
  flex: none;
  width: 26px;
  height: 240px;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  font-size: 0.6rem;
  color: var(--gray);
  text-align: right;
}

.timeline-day-col {
  display: flex;
  flex-direction: column;
  gap: 4px;
  flex: 1 1 0;
  min-width: 0;
}

.timeline-vtrack {
  position: relative;
  height: 240px;
  border-radius: 4px;
  border: 1px solid var(--hairline);
  overflow: hidden;
  background-image: linear-gradient(180deg, var(--off-white) 50%, var(--gray-light) 50%);
  background-size: 100% calc(100% / 9);
}

.timeline-day-col.today .timeline-vtrack {
  border-color: var(--maroon);
}

.timeline-vbar {
  position: absolute;
  left: 2px;
  right: 2px;
  border-radius: 3px;
  background: var(--maroon-gradient);
  cursor: pointer;
}

.timeline-vbar.open {
  background: var(--accent-red);
}

/* Job overlay -- a narrower bar inset inside the shift bar above, marking
   which specific job (if any) was being worked during that clocked-in
   period. Color is per-job (set inline by timesheet.js via jobColor()), so
   --gold-gradient here is only the fallback before JS assigns a color.
   "Still checked in" is now a pulsing ring rather than a swapped-in flat
   color, since the background itself carries job identity. */
.timeline-job-bar {
  position: absolute;
  left: 7px;
  right: 7px;
  z-index: 2;
  border-radius: 2px;
  background: var(--gold-gradient);
  border: 1px solid rgba(255, 255, 255, 0.5);
  cursor: pointer;
}

.timeline-job-bar.open {
  animation: timeline-job-bar-pulse 1.6s ease-in-out infinite;
}

@keyframes timeline-job-bar-pulse {
  0%, 100% { box-shadow: 0 0 0 0 rgba(255, 255, 255, 0.85); }
  50% { box-shadow: 0 0 0 3px rgba(255, 255, 255, 0.35); }
}

.timeline-legend {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 6px 16px;
  margin-bottom: 12px;
  font-size: 0.72rem;
  color: var(--slate);
}

.timeline-job-legend {
  margin-top: 8px;
  margin-bottom: 0;
}

.timeline-legend-item {
  display: flex;
  align-items: center;
  gap: 6px;
}

.timeline-legend-swatch {
  display: inline-block;
  width: 12px;
  height: 12px;
  border-radius: 3px;
}

.timeline-legend-swatch.shift {
  background: var(--maroon-gradient);
}

.timeline-legend-swatch.job {
  background: var(--gold-gradient);
}

.timeline-tooltip {
  display: none;
  position: fixed;
  z-index: 100;
  max-width: 200px;
  padding: 6px 10px;
  border-radius: 8px;
  background: var(--charcoal);
  color: var(--white);
  font-size: 0.75rem;
  line-height: 1.3;
  text-align: center;
  pointer-events: none;
  box-shadow: 0 6px 18px rgba(0, 0, 0, 0.25);
}

.timeline-day-label {
  text-align: center;
}

.timeline-day-name {
  display: block;
  font-size: 0.62rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.03em;
  color: var(--slate);
}

.timeline-day-date {
  display: block;
  font-size: 0.64rem;
  color: var(--gray);
}

.timeline-day-col.today .timeline-day-name,
.timeline-day-col.today .timeline-day-date {
  color: var(--maroon);
}

.week-calendar-total {
  text-align: right;
  font-size: 0.85rem;
  font-weight: 600;
  color: var(--maroon);
  margin-bottom: 16px;
}

.weekly-totals {
  background: var(--off-white);
  border: 1px solid var(--hairline);
  border-radius: 8px;
  padding: 10px 14px;
  margin-bottom: 16px;
}

.weekly-totals-title {
  font-size: 0.7rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--slate);
  margin-bottom: 4px;
}

.weekly-row {
  display: flex;
  justify-content: space-between;
  font-size: 0.9rem;
  padding: 4px 0;
}

.weekly-row span:last-child {
  font-weight: 600;
  color: var(--maroon);
}

.weekly-row.today {
  font-weight: 700;
}

.weekly-row.today span:first-child::after {
  content: " (today)";
  font-weight: 400;
  color: var(--slate);
  font-size: 0.8em;
}

button.small {
  flex: 0 0 auto;
  padding: 6px 10px;
  font-size: 0.85rem;
  border-radius: 6px;
}

button.small.tiny {
  padding: 4px 8px;
  font-size: 0.72rem;
  border-radius: 6px;
}

.btn-stack {
  display: flex;
  flex-direction: column;
  gap: 6px;
}

.total-hours {
  display: inline-block;
  padding: 6px 14px;
  border-radius: 999px;
  background: rgba(135, 4, 18, 0.06);
  font-size: 1rem;
  font-weight: 600;
  color: var(--maroon);
}

/* ==========================================================================
   Sign-in screen — matched to the McRay CRM's login look (2026-08-18).
   The CRM keeps a deep maroon-to-charcoal backdrop for the sign-in moment
   only, with a gold-rimmed white card floating on it; the rest of that app
   stays light. Same idea here: this block only ever applies to
   .top-banner.centered, which is the full-screen signed-out state, so the
   signed-in banner across the top of the app is untouched.
   ========================================================================== */

:root {
  /* Solid gold from the CRM's palette (its --gold), for hairline borders
     and rims where the existing --gold-gradient would be too busy. */
  --gold: #C9932F;
}

.top-banner.centered {
  /* Was the flat maroon banner gradient stretched full-screen. The radial
     puts the light at the top and lets the corners fall away to charcoal,
     which is what reads as depth rather than a flat red wall. */
  background: radial-gradient(circle at top, var(--maroon-dark) 0%, var(--charcoal) 65%);
  background-attachment: fixed;
}

/* The 2px gold hairline is a banner-bottom accent -- pinned to the bottom of
   a full-screen backdrop it just reads as a stray line, so it's dropped
   here (and only here). */
.top-banner.centered::after {
  display: none;
}

.top-banner.centered .login-box {
  border: 1.5px solid var(--gold);
  border-radius: 14px;
  padding: 40px 30px 34px;
  /* Deep drop shadow + a gold rim just outside the border, so the card
     reads as lit from above and sitting well off the background. */
  box-shadow:
    0 24px 60px rgba(0, 0, 0, 0.45),
    0 4px 12px rgba(0, 0, 0, 0.25),
    0 0 0 1px rgba(201, 147, 47, 0.18);
}

/* The gold top bar and the new full gold border together are too much --
   the border replaces it, matching the CRM card. */
.top-banner.centered .login-box::before {
  display: none;
}

.top-banner.centered .login-logo {
  height: 54px;
  margin-bottom: 6px;
}

/* Hairline gold rule under the ADMIN / TIME CLOCK label -- the one piece of
   ornament on the card, and the detail that makes it read as "considered"
   rather than just a white box. */
.top-banner.centered .login-title {
  position: relative;
  padding-bottom: 12px;
  margin-bottom: 6px;
}

.top-banner.centered .login-title::after {
  content: "";
  position: absolute;
  left: 50%;
  bottom: 0;
  transform: translateX(-50%);
  width: 56px;
  height: 2px;
  border-radius: 2px;
  background: var(--gold-gradient);
  opacity: 0.9;
}

/* `.top-banner .banner-inner input { flex: 1 1 110px }` is sized for the
   signed-in banner, which lays its controls out in a ROW. The reset-PIN
   panel is a COLUMN, so that flex-grow stretched the security-answer field
   to ~110px tall -- it read as a textarea. Height belongs to the padding
   rule above, not to flex, on this screen. */
.top-banner.centered .login-box input[type="text"] {
  flex: none;
  height: auto;
  line-height: normal;
  padding: 10px 14px;
  font-size: 0.95rem;
}
