/* Time, Billing & Leave — interface styles.
 *
 * Palette and typography taken from spsoft.com: Syne for headings,
 * Montserrat for body, crimson #f52255 against near-black #191919.
 *
 * This is an operational tool people open every day, often for two minutes at
 * a time to enter hours. It is styled to be quiet and legible rather than
 * expressive: the brand shows in the type, the accent and the header, and gets
 * out of the way of the numbers.
 */

:root {
  /* Brand */
  --sp-black: #191919;
  --sp-black-soft: #1d1d1d;
  --sp-crimson: #f52255;
  --sp-crimson-dark: #cd0d46;
  --sp-lime: #d7f522;

  /* Neutrals */
  --sp-grey-100: #f2f2f2;
  --sp-grey-200: #e8ebef;
  --sp-grey-300: #c9d4e2;
  --sp-grey-400: #bdbdbd;
  --sp-grey-500: #828282;
  --sp-slate: #505d68;

  /* Semantic. Amounts and states are read at a glance, so each state gets a
     colour that survives being seen out of the corner of the eye. */
  --sp-ok: #1a7f4b;
  --sp-ok-bg: #e8f5ee;
  --sp-warn: #a86400;
  --sp-warn-bg: #fdf3e2;
  --sp-danger: var(--sp-crimson-dark);
  --sp-danger-bg: #fdeaf0;
  --sp-info-bg: #eef2f8;

  --sp-bg: #ffffff;
  --sp-surface: #ffffff;
  --sp-page: #f7f8fa;
  --sp-text: var(--sp-black);
  --sp-text-muted: var(--sp-slate);
  --sp-border: var(--sp-grey-200);

  --sp-radius: 8px;
  --sp-radius-sm: 5px;
  --sp-shadow: 0 1px 2px rgba(25, 25, 25, 0.06), 0 1px 3px rgba(25, 25, 25, 0.04);
  --sp-shadow-lg: 0 4px 16px rgba(25, 25, 25, 0.09);

  --sp-font-head: "Syne", "Montserrat", system-ui, sans-serif;
  --sp-font-body: "Montserrat", system-ui, -apple-system, "Segoe UI", sans-serif;
  /* Hours and money must line up in columns; proportional digits do not. */
  --sp-font-num: ui-monospace, "SF Mono", "Cascadia Mono", Menlo, monospace;
}

*,
*::before,
*::after {
  box-sizing: border-box;
}

body {
  margin: 0;
  font-family: var(--sp-font-body);
  font-size: 15px;
  line-height: 1.55;
  color: var(--sp-text);
  background: var(--sp-page);
  -webkit-font-smoothing: antialiased;
}

h1, h2, h3, h4 {
  font-family: var(--sp-font-head);
  font-weight: 700;
  letter-spacing: -0.015em;
  margin: 0 0 0.6rem;
  line-height: 1.2;
}

h1 { font-size: 1.6rem; }
h2 { font-size: 1.2rem; }
h3 { font-size: 1rem; }

a {
  color: var(--sp-crimson-dark);
  text-decoration: none;
}
a:hover { text-decoration: underline; }

/* --- Layout ------------------------------------------------------------- */

.sp-header {
  background: var(--sp-black);
  color: #fff;
  padding: 0 1.5rem;
  display: flex;
  align-items: center;
  gap: 2rem;
  height: 58px;
  position: sticky;
  top: 0;
  z-index: 20;
}

.sp-brand {
  font-family: var(--sp-font-head);
  font-weight: 800;
  font-size: 1.05rem;
  letter-spacing: -0.02em;
  color: #fff;
  white-space: nowrap;
}
.sp-brand:hover { text-decoration: none; }
.sp-brand .dot { color: var(--sp-crimson); }

.sp-nav {
  display: flex;
  gap: 0.25rem;
  flex: 1;
  overflow-x: auto;
  /* A flex child defaults to min-width:auto, which lets the nav push the
     user block off the header and clip the last link. */
  min-width: 0;
}

.sp-nav a {
  color: rgba(255, 255, 255, 0.72);
  padding: 0.45rem 0.75rem;
  border-radius: var(--sp-radius-sm);
  font-size: 0.86rem;
  font-weight: 500;
  white-space: nowrap;
}
.sp-nav a:hover {
  color: #fff;
  background: rgba(255, 255, 255, 0.08);
  text-decoration: none;
}
.sp-nav a.active {
  color: #fff;
  background: var(--sp-crimson);
}

.sp-user {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  font-size: 0.82rem;
  color: rgba(255, 255, 255, 0.72);
  white-space: nowrap;
  /* Never squeezed by the nav: the sign-in identity and admin link must
     stay reachable at every width. */
  flex-shrink: 0;
}

.sp-main {
  max-width: 1240px;
  margin: 0 auto;
  padding: 1.75rem 1.5rem 4rem;
}

.sp-page-head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 1rem;
  flex-wrap: wrap;
  margin-bottom: 1.25rem;
}
.sp-page-head p { margin: 0; color: var(--sp-text-muted); font-size: 0.9rem; }

/* --- Cards -------------------------------------------------------------- */

.sp-card {
  background: var(--sp-surface);
  border: 1px solid var(--sp-border);
  border-radius: var(--sp-radius);
  box-shadow: var(--sp-shadow);
  margin-bottom: 1.25rem;
  overflow: hidden;
}

.sp-card-head {
  padding: 0.85rem 1.1rem;
  border-bottom: 1px solid var(--sp-border);
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  flex-wrap: wrap;
}
.sp-card-head h2, .sp-card-head h3 { margin: 0; }

.sp-card-body { padding: 1.1rem; }
.sp-card-body.flush { padding: 0; }

.sp-grid {
  display: grid;
  gap: 1rem;
  grid-template-columns: repeat(auto-fit, minmax(215px, 1fr));
  margin-bottom: 1.25rem;
}

/* --- Stat tiles --------------------------------------------------------- */

.sp-stat {
  background: var(--sp-surface);
  border: 1px solid var(--sp-border);
  border-radius: var(--sp-radius);
  padding: 1rem 1.1rem;
  box-shadow: var(--sp-shadow);
}
.sp-stat .label {
  font-size: 0.72rem;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--sp-text-muted);
  font-weight: 600;
  margin-bottom: 0.35rem;
}
.sp-stat .value {
  font-family: var(--sp-font-head);
  font-size: 1.65rem;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  letter-spacing: -0.02em;
}
.sp-stat .sub { font-size: 0.78rem; color: var(--sp-text-muted); margin-top: 0.15rem; }
.sp-stat.accent { border-left: 3px solid var(--sp-crimson); }

/* --- Tables ------------------------------------------------------------- */

.sp-table {
  width: 100%;
  border-collapse: collapse;
  font-size: 0.88rem;
}
.sp-table th {
  text-align: left;
  font-size: 0.7rem;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--sp-text-muted);
  font-weight: 700;
  padding: 0.6rem 0.85rem;
  border-bottom: 1px solid var(--sp-border);
  background: var(--sp-grey-100);
  white-space: nowrap;
}
.sp-table td {
  padding: 0.6rem 0.85rem;
  border-bottom: 1px solid var(--sp-border);
  vertical-align: middle;
}
.sp-table tbody tr:last-child td { border-bottom: none; }
.sp-table tbody tr:hover { background: var(--sp-grey-100); }
.sp-table .num {
  text-align: right;
  font-variant-numeric: tabular-nums;
  font-family: var(--sp-font-num);
  font-size: 0.85rem;
}
.sp-table-wrap { overflow-x: auto; }

/* --- Weekly timesheet grid ---------------------------------------------- */
/* The primary screen: a week of one person's time, project against day. */

.sp-week {
  width: 100%;
  border-collapse: collapse;
  font-size: 0.88rem;
}
.sp-week th {
  padding: 0.5rem 0.4rem;
  font-size: 0.7rem;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--sp-text-muted);
  font-weight: 700;
  border-bottom: 1px solid var(--sp-border);
  background: var(--sp-grey-100);
  text-align: center;
}
.sp-week th.project-col { text-align: left; min-width: 220px; }
.sp-week th .dow { display: block; font-size: 0.85rem; color: var(--sp-text); }
.sp-week th .date { display: block; font-weight: 500; font-size: 0.68rem; }

.sp-week td {
  padding: 0.3rem;
  border-bottom: 1px solid var(--sp-border);
  text-align: center;
}
.sp-week td.project-col {
  text-align: left;
  padding: 0.5rem 0.6rem;
  font-weight: 500;
}
.sp-week td.project-col .client {
  display: block;
  font-size: 0.74rem;
  color: var(--sp-text-muted);
  font-weight: 400;
}

/* Weekends and holidays are visibly not working days, so a gap there reads as
   expected rather than as missing time. */
.sp-week .off { background: var(--sp-grey-100); }
/* Approved leave: no hours are expected, and the reason is visible. */
.sp-week .on-leave {
  background: var(--sp-info-bg);
  color: var(--sp-slate);
  font-size: 0.7rem;
  font-weight: 600;
}

.sp-hours {
  width: 62px;
  padding: 0.35rem 0.2rem;
  text-align: center;
  border: 1px solid var(--sp-grey-300);
  border-radius: var(--sp-radius-sm);
  font-family: var(--sp-font-num);
  font-size: 0.85rem;
  font-variant-numeric: tabular-nums;
  background: #fff;
  color: var(--sp-text);
}
.sp-hours:focus {
  outline: none;
  border-color: var(--sp-crimson);
  box-shadow: 0 0 0 3px rgba(245, 34, 85, 0.14);
}
.sp-hours:disabled {
  background: var(--sp-grey-100);
  color: var(--sp-grey-500);
  cursor: not-allowed;
}
.sp-hours.saved {
  border-color: var(--sp-ok);
  background: var(--sp-ok-bg);
}

.sp-week tfoot td {
  font-weight: 700;
  background: var(--sp-grey-100);
  font-family: var(--sp-font-num);
  font-variant-numeric: tabular-nums;
}
/* A day short of or over the person's schedule is worth noticing while
   entering, not at submission. */
.sp-day-total.under { color: var(--sp-warn); }
.sp-day-total.over { color: var(--sp-danger); }
.sp-day-total.exact { color: var(--sp-ok); }

/* --- Badges ------------------------------------------------------------- */

.sp-badge {
  display: inline-block;
  padding: 0.16rem 0.5rem;
  border-radius: 100px;
  font-size: 0.7rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  white-space: nowrap;
}
.sp-badge.draft { background: var(--sp-grey-200); color: var(--sp-slate); }
.sp-badge.submitted { background: var(--sp-warn-bg); color: var(--sp-warn); }
.sp-badge.approved { background: var(--sp-ok-bg); color: var(--sp-ok); }
.sp-badge.rejected { background: var(--sp-danger-bg); color: var(--sp-danger); }
.sp-badge.locked { background: var(--sp-black); color: #fff; }
.sp-badge.pending { background: var(--sp-warn-bg); color: var(--sp-warn); }
.sp-badge.cancelled { background: var(--sp-grey-200); color: var(--sp-grey-500); }
.sp-badge.billable { background: var(--sp-ok-bg); color: var(--sp-ok); }
.sp-badge.non-billable { background: var(--sp-grey-200); color: var(--sp-slate); }
.sp-badge.contractor { background: #efe7fb; color: #5b3a9e; }

/* --- Buttons ------------------------------------------------------------ */

.sp-btn {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  padding: 0.5rem 0.95rem;
  border-radius: var(--sp-radius-sm);
  border: 1px solid transparent;
  font-family: var(--sp-font-body);
  font-size: 0.85rem;
  font-weight: 600;
  cursor: pointer;
  background: var(--sp-black);
  color: #fff;
  transition: background 0.12s ease;
}
.sp-btn:hover { background: #000; text-decoration: none; }
.sp-btn.primary { background: var(--sp-crimson); }
.sp-btn.primary:hover { background: var(--sp-crimson-dark); }
.sp-btn.ghost {
  background: transparent;
  border-color: var(--sp-grey-300);
  color: var(--sp-text);
}
.sp-btn.ghost:hover { background: var(--sp-grey-100); }
.sp-btn.ok { background: var(--sp-ok); }
.sp-btn.danger { background: var(--sp-crimson-dark); }
.sp-btn.sm { padding: 0.32rem 0.6rem; font-size: 0.78rem; }
.sp-btn:disabled { opacity: 0.45; cursor: not-allowed; }

.sp-actions { display: flex; gap: 0.5rem; flex-wrap: wrap; align-items: center; }

/* --- Forms -------------------------------------------------------------- */

.sp-field { margin-bottom: 0.95rem; }
.sp-field label {
  display: block;
  font-size: 0.78rem;
  font-weight: 700;
  margin-bottom: 0.3rem;
  color: var(--sp-text);
}
.sp-field .hint { font-size: 0.76rem; color: var(--sp-text-muted); margin-top: 0.22rem; }

.sp-input, .sp-select, .sp-textarea {
  width: 100%;
  padding: 0.5rem 0.65rem;
  border: 1px solid var(--sp-grey-300);
  border-radius: var(--sp-radius-sm);
  font-family: var(--sp-font-body);
  font-size: 0.88rem;
  background: #fff;
  color: var(--sp-text);
}
.sp-input:focus, .sp-select:focus, .sp-textarea:focus {
  outline: none;
  border-color: var(--sp-crimson);
  box-shadow: 0 0 0 3px rgba(245, 34, 85, 0.14);
}
.sp-textarea { min-height: 74px; resize: vertical; }
.sp-form-row {
  display: grid;
  gap: 1rem;
  grid-template-columns: repeat(auto-fit, minmax(190px, 1fr));
}

/* --- Messages ----------------------------------------------------------- */

.sp-note {
  padding: 0.7rem 0.9rem;
  border-radius: var(--sp-radius-sm);
  font-size: 0.86rem;
  margin-bottom: 0.95rem;
  border-left: 3px solid;
}
.sp-note.info { background: var(--sp-info-bg); border-color: var(--sp-slate); }
.sp-note.ok { background: var(--sp-ok-bg); border-color: var(--sp-ok); color: #145f38; }
.sp-note.warn { background: var(--sp-warn-bg); border-color: var(--sp-warn); color: #7a4900; }
.sp-note.error { background: var(--sp-danger-bg); border-color: var(--sp-danger); color: var(--sp-danger); }

.sp-empty {
  padding: 2.4rem 1rem;
  text-align: center;
  color: var(--sp-text-muted);
  font-size: 0.9rem;
}

/* --- Calendar ----------------------------------------------------------- */

.sp-cal { width: 100%; border-collapse: collapse; font-size: 0.82rem; }
.sp-cal th {
  padding: 0.45rem 0.3rem;
  font-size: 0.66rem;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--sp-text-muted);
  border-bottom: 1px solid var(--sp-border);
  background: var(--sp-grey-100);
  text-align: center;
  min-width: 34px;
}
.sp-cal th.person-col { text-align: left; min-width: 175px; }
.sp-cal td {
  border-bottom: 1px solid var(--sp-border);
  border-right: 1px solid var(--sp-grey-100);
  height: 30px;
  text-align: center;
  padding: 0;
}
.sp-cal td.person-col { text-align: left; padding: 0.35rem 0.6rem; font-weight: 500; }
.sp-cal td.away { background: var(--sp-crimson); }
.sp-cal td.away-unpaid {
  /* Contractor unavailability is not leave; it reads differently on purpose. */
  background: repeating-linear-gradient(
    45deg, var(--sp-slate), var(--sp-slate) 3px, transparent 3px, transparent 6px
  );
}
.sp-cal td.weekend { background: var(--sp-grey-100); }

.sp-legend {
  display: flex;
  gap: 1rem;
  flex-wrap: wrap;
  font-size: 0.76rem;
  color: var(--sp-text-muted);
  padding: 0.7rem 1.1rem;
}
.sp-legend span { display: inline-flex; align-items: center; gap: 0.35rem; }
.sp-swatch {
  width: 13px;
  height: 13px;
  border-radius: 3px;
  display: inline-block;
  border: 1px solid var(--sp-border);
}

/* --- Utility ------------------------------------------------------------ */

.muted { color: var(--sp-text-muted); }
.num { font-variant-numeric: tabular-nums; font-family: var(--sp-font-num); }
.right { text-align: right; }
.nowrap { white-space: nowrap; }
.stack > * + * { margin-top: 0.85rem; }
.htmx-request { opacity: 0.55; transition: opacity 0.1s; }

@media (max-width: 720px) {
  .sp-header { gap: 0.75rem; padding: 0 0.85rem; }
  .sp-user .name { display: none; }
  .sp-main { padding: 1.1rem 0.85rem 3rem; }
}

/* --- Timer -------------------------------------------------------------- */
/* Specification A.2's start/stop timer. Quiet when idle, unmistakable when
   running: someone who forgets a timer is running bills the wrong day. */

.sp-timer {
  background: var(--sp-surface);
  border: 1px solid var(--sp-border);
  border-radius: var(--sp-radius);
  box-shadow: var(--sp-shadow);
  padding: 0.75rem 1.1rem;
  margin-bottom: 1.25rem;
}
.sp-timer.running {
  border-left: 3px solid var(--sp-crimson);
  background: linear-gradient(to right, var(--sp-danger-bg), var(--sp-surface) 40%);
}
.sp-timer-body {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  flex-wrap: wrap;
}
.sp-timer-label {
  font-size: 0.72rem;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  font-weight: 700;
  color: var(--sp-text-muted);
}
.sp-timer-detail { display: flex; flex-direction: column; line-height: 1.3; flex: 1; }
.sp-timer-detail .muted { font-size: 0.78rem; }
.sp-timer-elapsed {
  font-family: var(--sp-font-num);
  font-size: 1.3rem;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  color: var(--sp-crimson-dark);
}
.sp-timer-dot {
  width: 9px;
  height: 9px;
  border-radius: 50%;
  background: var(--sp-crimson);
  animation: sp-pulse 2s ease-in-out infinite;
}
@keyframes sp-pulse {
  0%, 100% { opacity: 1; }
  50% { opacity: 0.3; }
}
/* Respect a reduced-motion preference: a pulsing dot is decoration. */
@media (prefers-reduced-motion: reduce) {
  .sp-timer-dot { animation: none; }
}

/* --- Cell detail -------------------------------------------------------- */

.sp-cell-inner {
  position: relative;
  display: inline-flex;
  align-items: center;
}
.sp-cell-detail {
  position: absolute;
  top: -3px;
  right: -6px;
  width: 15px;
  height: 15px;
  padding: 0;
  border: none;
  border-radius: 3px;
  background: var(--sp-grey-200);
  color: var(--sp-slate);
  font-size: 0.6rem;
  line-height: 1;
  cursor: pointer;
  opacity: 0;
  transition: opacity 0.12s;
}
.sp-cell:hover .sp-cell-detail,
.sp-cell-detail:focus { opacity: 1; }
/* An entry carrying a task or marked non-billable stays visible, so the
   grid shows at a glance where the exceptions are. */
.sp-cell-detail.has-detail {
  opacity: 1;
  background: var(--sp-crimson);
  color: #fff;
}
.sp-cell-error {
  font-size: 0.66rem;
  color: var(--sp-danger);
  margin-top: 0.15rem;
  line-height: 1.2;
}

.sp-detail-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  margin-bottom: 0.9rem;
  padding-bottom: 0.6rem;
  border-bottom: 1px solid var(--sp-border);
}
.sp-detail-head .muted { display: block; font-size: 0.8rem; }

.sp-add-row {
  padding: 0.85rem 1.1rem;
  border-top: 1px solid var(--sp-border);
  background: var(--sp-grey-100);
}

/* --- Approvals ---------------------------------------------------------- */

.sp-bulk-bar { position: sticky; top: 58px; z-index: 10; }
.sp-bulk-bar .sp-card-body { padding: 0.7rem 1.1rem; }

/* Per-day hours, so the shape of the week is visible rather than just its
   total. */
.sp-daybar { display: flex; gap: 0.4rem; flex-wrap: wrap; }
.sp-daybar-item {
  display: flex;
  flex-direction: column;
  align-items: center;
  padding: 0.4rem 0.6rem;
  border: 1px solid var(--sp-border);
  border-radius: var(--sp-radius-sm);
  background: var(--sp-grey-100);
  min-width: 62px;
}
.sp-daybar-item .d {
  font-size: 0.66rem;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--sp-text-muted);
  font-weight: 600;
}
.sp-daybar-item .h {
  font-family: var(--sp-font-num);
  font-variant-numeric: tabular-nums;
  font-weight: 700;
  font-size: 0.9rem;
}
.sp-daybar-item.unusual {
  border-color: var(--sp-warn);
  background: var(--sp-warn-bg);
}
.sp-daybar-item.unusual .h { color: var(--sp-warn); }

.sp-empty p { margin: 0 0 0.4rem; }
.sp-empty p:last-child { margin-bottom: 0; }
