/* Ballard Electric and Appliance Repair — mobile-first base styles.
 *
 * Phones are the primary target: a subcontractor uses this outdoors in daylight
 * glare, in the rain with wet hands, and one-handed behind an appliance. That
 * scene drives three decisions here and is worth stating so nobody "tidies"
 * them away later:
 *
 *   1. LIGHT IS THE TUNED THEME. Dark mode follows the phone, but the hard
 *      condition is sunlight on a screen, and dark-on-bright is worse there.
 *   2. HIGH CONTRAST, NO THIN GREYS. Low-contrast secondary text is invisible
 *      outdoors — the muted tone here is tinted from the brand, not washed out.
 *   3. NORMAL CONTROL SIZES, HONEST SPACING. Confirmed with the owner: standard
 *      sizes are fine. Rows are separated enough that a wet finger does not hit
 *      the neighbour, which is a spacing problem, not a size one.
 *
 * Architecture adopted from the sibling Gringo Cats dashboard, proven in the
 * field on a phone. Recoloured to the approved brand; structure kept.
 */

:root {
  /* Surfaces and ink */
  --bg: #f1f3f1;
  --card: #ffffff;
  --ink: #111c1a;          /* tide ink — near-black with a green bias */
  --ink-soft: #33423f;
  --muted: #55645f;        /* tinted from the brand hue, never a flat grey */
  --line: #d7ded9;
  --line-strong: #bcc7c1;

  /* Brand and state */
  --brand: #0d4f52;        /* Pacific teal */
  --brand-ink: #ffffff;
  --brand-soft: #e3eeed;
  --accent: #a8762f;       /* weathered brass — used sparingly, one job at a time */
  --accent-soft: #f6efe3;
  --alert: #9a2b21;
  --warn: #8a5a00;
  --ok: #1d6b45;

  /* Spacing scale (4px base) — use these, not one-off values */
  --s1: 4px;  --s2: 8px;  --s3: 12px; --s4: 16px;
  --s5: 24px; --s6: 32px; --s7: 48px;

  --r-sm: 8px; --r-md: 10px; --r-lg: 14px; --r-pill: 999px;

  --t-xs: .75rem; --t-sm: .8125rem; --t-md: .875rem; --t-base: 1rem;
  --t-lg: 1.125rem; --t-xl: 1.375rem; --t-2xl: 1.75rem;

  --tap: 46px;
  --ease: cubic-bezier(.2, .7, .3, 1);
}

@media (prefers-color-scheme: dark) {
  :root {
    --bg: #0d1513; --card: #16211f; --ink: #e9ede8; --ink-soft: #c3cdc8;
    --muted: #9aa9a4; --line: #253431; --line-strong: #354642;
    --brand: #5fbec2; --brand-ink: #06201f; --brand-soft: #14302f;
    --accent: #d5a356; --accent-soft: #2c2418;
    --alert: #ff9b93; --warn: #f0c66a; --ok: #7fd3a6;
  }
}

* { box-sizing: border-box; }

html { -webkit-text-size-adjust: 100%; }

body {
  margin: 0;
  background: var(--bg);
  color: var(--ink);
  font: var(--t-base)/1.5 system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
  -webkit-font-smoothing: antialiased;
}

/* Money, hours and counts line up column-wise wherever they appear. */
.num, td.num, .money { font-variant-numeric: tabular-nums; }

/* Every interactive element gets a visible keyboard focus ring — including the
 * ones drawn as cards or table rows, which are easy to forget. */
:focus-visible {
  outline: 3px solid var(--accent);
  outline-offset: 2px;
  border-radius: var(--r-sm);
}

a { color: var(--brand); text-decoration-thickness: 1px; text-underline-offset: 2px; }
/* Deliberately no a:visited rule. A pseudo-class counts towards specificity and
 * quietly beats later single-class rules. */

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

.topbar {
  position: sticky; top: 0; z-index: 20;
  display: flex; align-items: center; gap: var(--s3);
  padding: var(--s2) var(--s4);
  background: var(--brand); color: var(--brand-ink);
  /* Sticky: every pixel it grows is taken off every screen below it. */
}
.topbar a { color: var(--brand-ink); text-decoration: none; }
.brand { display: flex; align-items: center; gap: var(--s2); font-weight: 700; letter-spacing: -.01em; }
.brand svg { display: block; width: 30px; height: 30px; flex: none; }
/* On a phone the mark carries the identity; the full trading name will not fit
 * beside navigation and is not needed by someone already logged in. */
.brand-name { font-size: var(--t-lg); }
@media (max-width: 30rem) { .brand-name { display: none; } }

.topnav { margin-left: auto; display: flex; align-items: center; gap: var(--s4); font-size: var(--t-md); }
.topnav a { padding: var(--s2) 0; }
.who { font-size: var(--t-xs); opacity: .85; }

/* -------------------------------------------------------------- layout --- */

.wrap { max-width: 62rem; margin: 0 auto; padding: var(--s4) var(--s4) var(--s7); }
/* Running prose is capped near 70 characters; tables and lists are not. */
.prose { max-width: 68ch; }

/* More space above a heading than below it: a heading belongs to what follows. */
h1 { font-size: var(--t-2xl); line-height: 1.2; letter-spacing: -.02em; margin: var(--s5) 0 var(--s2); text-wrap: balance; }
h2 { font-size: var(--t-lg); line-height: 1.3; letter-spacing: -.01em; margin: var(--s5) 0 var(--s2); }
h3 { font-size: var(--t-base); margin: var(--s4) 0 var(--s2); }
p  { margin: 0 0 var(--s3); }
.hint { color: var(--muted); font-size: var(--t-md); }
.foot { text-align: center; color: var(--muted); font-size: var(--t-xs); padding: var(--s6) var(--s4); }

/* Cards — flat, bounded by a hairline. No shadow: depth is declared once, by
 * the sticky top bar, and nowhere else. */
.card {
  background: var(--card); border: 1px solid var(--line);
  border-radius: var(--r-lg); padding: var(--s4);
}
.card + .card { margin-top: var(--s3); }

/* -------------------------------------------------------------- lists ---- */

/* The work list. A row is a whole tap target, and rows are separated rather
 * than merely divided, so a wet finger cannot catch the neighbour. */
.rows { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--s2); }
.row {
  display: block; background: var(--card); border: 1px solid var(--line);
  border-radius: var(--r-md); padding: var(--s3) var(--s4);
  color: inherit; text-decoration: none;
  min-height: var(--tap);
  transition: border-color 120ms var(--ease), background 120ms var(--ease);
}
.row:hover { border-color: var(--line-strong); background: var(--brand-soft); }
.row-top { display: flex; align-items: baseline; gap: var(--s3); }
.row-title { font-weight: 600; }
.row-meta { margin-left: auto; color: var(--muted); font-size: var(--t-sm); white-space: nowrap; }
/* A row is a link, so it says so — a chevron on the right, and the whole row
   lifts on hover. Without it a tappable card looks like a read-only panel. */
a.row { position: relative; padding-right: var(--s6); }
a.row::after {
  content: ""; position: absolute; right: var(--s4); top: 50%;
  width: 8px; height: 8px; margin-top: -5px;
  border-right: 2px solid var(--muted); border-bottom: 2px solid var(--muted);
  transform: rotate(-45deg); opacity: .7;
}
a.row:hover::after { border-color: var(--brand); opacity: 1; }
.row-sub { color: var(--muted); font-size: var(--t-md); margin-top: 2px; }

/* Town groups. Ucluelet is a 40-minute drive paid for once, so work there is
 * batched — the grouping is the point of the screen, not decoration. */
.group-head {
  display: flex; align-items: baseline; gap: var(--s2);
  margin: var(--s5) 0 var(--s2); padding-bottom: var(--s1);
  border-bottom: 1px solid var(--line-strong);
}
.group-head h2 { margin: 0; }
.group-count { color: var(--muted); font-size: var(--t-sm); }

/* ------------------------------------------------------------- chips ----- */

.chip {
  display: inline-block; font-size: var(--t-xs); font-weight: 700;
  padding: 2px var(--s2); border-radius: var(--r-pill);
  border: 1px solid var(--line-strong); color: var(--muted);
  white-space: nowrap;
}
/* Priority 1 earns the alert colour; the rest stay quiet so it means something. */
.pri-1 { color: var(--alert); border-color: currentColor; font-weight: 700; }
.pri-2 { color: var(--warn); border-color: currentColor; }
.pri-3, .pri-4 { color: var(--muted); }
.chip-parts { color: var(--accent); border-color: currentColor; background: var(--accent-soft); }
.chip-overdue { color: var(--alert); border-color: currentColor; }

/* ------------------------------------------------------------ buttons ---- */

.btn, button, input[type="submit"] {
  display: inline-flex; align-items: center; justify-content: center; gap: var(--s2);
  min-height: var(--tap); padding: 0 var(--s4);
  border-radius: var(--r-md); border: 1px solid var(--line-strong);
  background: var(--card); color: var(--ink);
  font: inherit; font-weight: 600; cursor: pointer;
  transition: background 120ms var(--ease), border-color 120ms var(--ease);
}
.btn-primary { background: var(--brand); border-color: var(--brand); color: var(--brand-ink); }
.btn-primary:hover { filter: brightness(1.08); }
.btn-danger { color: var(--alert); border-color: currentColor; }
.btn:disabled, button:disabled { opacity: .5; cursor: not-allowed; }
/* The view you are already looking at: still reads as the selected one, but does
   not behave like something to press. */
.is-current { cursor: default; text-decoration: none; }
.btn-block { width: 100%; }
.btn-row { display: flex; flex-wrap: wrap; gap: var(--s2); margin-top: var(--s4); }

/* --------------------------------------------------------------- forms --- */

form label { display: block; margin: var(--s4) 0 var(--s1); font-weight: 600; font-size: var(--t-md); }
input, select, textarea {
  width: 100%; min-height: var(--tap); padding: var(--s2) var(--s3);
  border: 1px solid var(--line-strong); border-radius: var(--r-md);
  background: var(--card); color: var(--ink); font: inherit;
}
textarea { min-height: 6rem; resize: vertical; line-height: 1.5; }
input::placeholder, textarea::placeholder { color: var(--muted); }
.field-hint { color: var(--muted); font-size: var(--t-sm); margin-top: var(--s1); }
.field-error { color: var(--alert); font-size: var(--t-sm); margin-top: var(--s1); font-weight: 600; }
input[aria-invalid="true"], textarea[aria-invalid="true"] { border-color: var(--alert); }

/* ------------------------------------------------------------ messages --- */

.flash, .alert {
  padding: var(--s3) var(--s4); border-radius: var(--r-md);
  border: 1px solid; margin: var(--s4) 0; font-size: var(--t-md);
}
.flash { background: var(--brand-soft); border-color: var(--brand); color: var(--ink); }
.alert { background: var(--card); border-color: var(--alert); color: var(--alert); font-weight: 600; }
/* A link inside a coloured message belongs to that message, not to the page. */
.flash a, .alert a { color: inherit; }

/* Offline. Shown when a save could not reach the server — the app is online-only
 * by decision, so it must say so plainly rather than fail silently or, worse,
 * appear to have succeeded. */
.offline-banner {
  position: sticky; top: 0; z-index: 30;
  background: var(--alert); color: #fff; text-align: center;
  padding: var(--s2) var(--s4); font-size: var(--t-md); font-weight: 600;
}

/* --------------------------------------------------------------- empty --- */

/* Three jobs is a normal day, and an empty list is a normal morning. The empty
 * state has to read as finished work, not as a page that failed to load. */
.empty {
  text-align: center; padding: var(--s7) var(--s4);
  color: var(--muted); border: 1px dashed var(--line-strong);
  border-radius: var(--r-lg);
}
.empty svg { width: 40px; height: 40px; margin-bottom: var(--s3); opacity: .5; }
.empty p { margin: 0; }
.empty strong { display: block; color: var(--ink); font-size: var(--t-lg); margin-bottom: var(--s1); }

/* -------------------------------------------------------------- tables --- */

table { width: 100%; border-collapse: collapse; font-size: var(--t-md); }
th {
  text-align: left; font-size: var(--t-xs); text-transform: uppercase;
  letter-spacing: .06em; color: var(--muted); font-weight: 700;
  padding: var(--s2) var(--s2); border-bottom: 1px solid var(--line-strong);
}
td { padding: var(--s3) var(--s2); border-bottom: 1px solid var(--line); vertical-align: top; }
td.r, th.r { text-align: right; }
.table-scroll { overflow-x: auto; }

/* -------------------------------------------------------------- photos --- */

/* Square tiles so a portrait and a landscape shot sit in one grid without the
   row jumping about. Used on the review tray and the job page. */
.thumbs {
  display: grid; gap: var(--s2); margin: var(--s3) 0;
  grid-template-columns: repeat(auto-fill, minmax(84px, 1fr));
}
.thumb { position: relative; aspect-ratio: 1; display: block; }
.photo-actions { display: flex; gap: var(--s2); flex-wrap: wrap; }
.photo-actions .btn { flex: 1 1 10rem; margin: 0; font-weight: 600; }
.thumb img {
  width: 100%; height: 100%; object-fit: cover;
  border-radius: var(--r-md); border: 1px solid var(--line-strong); display: block;
}

/* ------------------------------------------------------------- utility --- */

.stack { display: grid; gap: var(--s3); }
.between { display: flex; align-items: center; gap: var(--s3); }
.between > :last-child { margin-left: auto; }
.sr-only {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

@media (prefers-reduced-motion: reduce) {
  * { transition-duration: 0.01ms !important; animation-duration: 0.01ms !important; }
}
