/* Taimaka brand — from "2025 Taimaka Branding.docx"
     Beige  #f8f4ec  backgrounds, most dominant colour
     Navy   #282c3c  most text, background accenting
     Gold   #b4945b  some text, background accenting
     White            also used for backgrounds
     Playfair Display titles · Cormorant subtitles · Open Sans body · Amatic SC logo
   Fonts are self-hosted from the branding document, so the portal needs no
   external CDN — staff on a weak connection get the fallback stack instantly
   and the brand face swaps in when it arrives. */

/* woff2 with the .ttf kept as a fallback. The browser takes the first format it
   understands, so every phone made in the last decade downloads 155 KB rather
   than 359 KB — on a first visit over mobile data that is most of the page.
   Anything too old for woff2 still gets the .ttf and looks the same. */
@font-face { font-family: 'Open Sans';
             src: url('/fonts/OpenSans-regular.woff2') format('woff2'),
                  url('/fonts/OpenSans-regular.ttf') format('truetype');
             font-weight: 400; font-display: swap; }
@font-face { font-family: 'Open Sans';
             src: url('/fonts/OpenSans-bold.woff2') format('woff2'),
                  url('/fonts/OpenSans-bold.ttf') format('truetype');
             font-weight: 700; font-display: swap; }
@font-face { font-family: 'Playfair Display';
             src: url('/fonts/PlayfairDisplay-bold.woff2') format('woff2'),
                  url('/fonts/PlayfairDisplay-bold.ttf') format('truetype');
             font-weight: 700; font-display: swap; }

/* Width includes padding and border. Without it every full-width input and
   card was a few pixels wider than a phone, and Android Chrome then zoomed the
   whole page out to fit it, so everything looked tiny (Oct 2026). */
*, *::before, *::after { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; }

:root {
  --beige: #f8f4ec;
  --navy: #282c3c;
  --gold: #b4945b;
  --white: #fff;
  --ink-soft: rgba(40, 44, 60, .68);
  --ink-faint: rgba(40, 44, 60, .5);
  --rule: rgba(40, 44, 60, .14);
  --gold-soft: rgba(180, 148, 91, .16);
  --navy-soft: rgba(40, 44, 60, .07);
  --danger: #9b2c22;
  --danger-soft: rgba(155, 44, 34, .1);
  --ok: #3f6b4a;
  --ok-soft: rgba(63, 107, 74, .13);
  /* Two hues beyond the brand pair, so a status reads before the word does.
     Both are desaturated to sit on beige next to the gold rather than fight it,
     and both pass AA as text on the beige ground (teal 6.0:1, gold ink 5.2:1).
     Four meanings, one hue each — teal waiting, gold needs you, green settled,
     red wrong — and anything dormant stays neutral. */
  --info: #2f6472;
  --info-soft: rgba(47, 100, 114, .12);
  --gold-ink: #7d6231;   /* --gold is a fill, not a text colour; this is the text one */
  /* The brand palette is light. Declaring it stops the browser tinting form
     controls for dark mode and leaving them unreadable on beige. */
  color-scheme: light;
  font: 16px/1.55 'Open Sans', system-ui, -apple-system, Segoe UI, sans-serif;
}

body { margin: 0; background: var(--beige); color: var(--navy); }
main { max-width: 32rem; margin: 0 auto; padding: 1.25rem 1rem 3.5rem; }

/* Navy header bar. The logo's own background is #242a3f, which is
   indistinguishable from the brand navy, so the badge reads as seamless. */
header.brand {
  display: flex; align-items: center; gap: .7rem;
  background: var(--navy); color: var(--white);
  padding: .6rem 1rem;
}
header.brand .brand-mark { height: 38px; width: auto; display: block; }
header.brand .brand-title {
  font-family: 'Playfair Display', Georgia, serif; font-weight: 700;
  font-size: 1.05rem; letter-spacing: .01em;
  margin: 0;   /* it is the page h1, so cancel the document heading margin */
}
header.brand .brand-right { margin-left: auto; font-size: .82rem; opacity: .8; }

h1, h2, h3 { font-family: 'Playfair Display', Georgia, serif; font-weight: 700; line-height: 1.25; }
h1 { font-size: 1.35rem; margin: 0 0 .8rem; }
h2 { font-size: 1.08rem; margin: 1.5rem 0 .4rem; }
a { color: var(--navy); text-decoration-color: var(--gold); text-underline-offset: 2px; }

label { display: block; margin: .8rem 0 .25rem; font-weight: 700; font-size: .86rem; }
input, select, textarea {
  width: 100%; padding: .62rem .7rem; font: inherit; color: var(--navy);
  background: var(--white); border: 1px solid var(--rule); border-radius: .4rem;
}
textarea { min-height: 4.5rem; resize: vertical; font-family: inherit; }
input:focus-visible, select:focus-visible, textarea:focus-visible, button:focus-visible {
  outline: 2px solid var(--gold); outline-offset: 1px;
}
input::placeholder { color: var(--ink-faint); }

button {
  margin-top: 1rem; padding: .68rem 1.15rem; font: inherit; font-weight: 700;
  border: 0; border-radius: .4rem; background: var(--navy); color: var(--white); cursor: pointer;
}
button:hover { background: #1e2230; }
button.sub { background: var(--navy-soft); color: var(--navy); font-weight: 400; }
button.danger { background: var(--danger); }
button.link {
  display: block; background: none; color: var(--navy); padding: 0; margin-top: .85rem;
  font-weight: 400; text-decoration: underline; text-decoration-color: var(--gold);
  text-underline-offset: 3px;
}
button.link:hover { background: none; color: var(--gold); }
/* A link that sits in a line of text, e.g. the actions on one roster row. */
button.link.inline { display: inline; margin: 0; }

/* The tints are see-through, and the bar is sticky: laid over the page colour
   so what scrolls underneath does not show through the text. */
.msg { margin: 1rem 0; padding: .6rem .8rem; border-radius: .4rem;
       background: linear-gradient(var(--gold-soft), var(--gold-soft)), var(--beige);
       border-left: 3px solid var(--gold); font-size: .92rem; }
.msg.err { background: linear-gradient(var(--danger-soft), var(--danger-soft)), var(--beige);
           border-left-color: var(--danger); color: var(--danger); }

.big { font-family: 'Playfair Display', Georgia, serif; font-size: 1.7rem; font-weight: 700;
       letter-spacing: .04em; margin: .2rem 0; }
.muted { color: var(--ink-soft); }
.mono { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; }

fieldset { border: 1px solid var(--rule); border-radius: .5rem; padding: .9rem 1rem; background: var(--white); }
legend { font-weight: 700; font-size: .86rem; padding: 0 .35rem; }
hr { border: 0; border-top: 1px solid var(--rule); margin: 1.5rem 0; }

table { border-collapse: collapse; width: 100%; margin-top: .6rem; font-size: .92rem; }
th, td { text-align: left; padding: .45rem .5rem; border-bottom: 1px solid var(--rule); vertical-align: middle; }
th { font-size: .74rem; text-transform: uppercase; letter-spacing: .05em; color: var(--ink-soft); font-weight: 700; }
/* Payroll review tables: every other row tinted, so a row reads across (Anna,
   7 Oct 2026). Approved people turn green. */
table.rv { background: var(--white); }
table.rv tbody tr:nth-child(even) td { background: var(--navy-soft); }
table.rv tbody tr.ok td { background: var(--ok-soft); }

section[hidden], div[hidden], nav[hidden], button[hidden] { display: none !important; }

/* --- components --------------------------------------------------------------
   Everything below was previously an unstyled <button> falling through to the
   primary rule above, which is why navigation, sign-out and the PIN reveal all
   looked like the submit button. A button that is not the main action on the
   screen must not look like one. */

/* Tab strip. ONE ROW, scrolling sideways, with a fade on the right edge so it
   is visible that there is more.

   It has been all three things: scrolling with the scrollbar hidden (the last
   tab was unreachable-looking), then wrapping to two rows (which read as a
   mistake). The fade is what the original was missing — the scroll was right,
   the silence about it was not. Eight tabs is what a program officer sees, and
   Transport has to be findable at a glance rather than filed under something.

   The mask is on a wrapper so the buttons keep their own hit areas; a gradient
   over the nav itself would swallow taps at the right edge. */
.tabs { position: relative; margin: 0 -1rem 1.1rem; }
.tabs::after {
  content: ""; position: absolute; top: 0; right: 0; bottom: 1px; width: 2.2rem;
  pointer-events: none;
  background: linear-gradient(to right, rgba(247, 244, 237, 0), var(--beige) 75%);
}
nav {
  display: flex; flex-wrap: nowrap; gap: 1.15rem;
  overflow-x: auto; scrollbar-width: none; -webkit-overflow-scrolling: touch;
  scroll-snap-type: x proximity;
  margin: 0; padding: 0 2.2rem 0 1rem;
  border-bottom: 1px solid var(--rule);
}
nav::-webkit-scrollbar { display: none; }
nav button {
  margin: 0; padding: .62rem .1rem; flex: 0 0 auto; white-space: nowrap;
  scroll-snap-align: start;
  background: none; color: var(--ink-soft); font-size: .9rem; font-weight: 700;
  border-radius: 0; border-bottom: 2px solid transparent;
}
nav button:hover { background: none; color: var(--navy); }
nav button[aria-current="true"] { color: var(--navy); border-bottom-color: var(--gold); }

/* Sub-navigation inside a tab. Same bar, quieter: it sits under a heading that
   has already said where you are, and it must not compete with the main one. */
nav.sub { gap: .95rem; margin: .2rem 0 1rem; padding: 0; }
nav.sub button { padding: .45rem .1rem; font-size: .84rem; }
nav.sub .badge { background: var(--info); }

/* Sign out lives on the navy bar, so the primary navy fill made it invisible. */
header.brand .signout {
  margin: 0 0 0 auto; padding: .28rem .7rem; font-size: .8rem; font-weight: 400;
  background: transparent; color: var(--white); border-radius: .3rem;
  border: 1px solid rgba(255, 255, 255, .35);
}
header.brand .signout:hover { background: rgba(255, 255, 255, .14); }

/* reveal.js wraps each password field in this. Without it the Show button
   dropped below a full-width input looking like the submit control. */
.reveal { display: flex; align-items: center; gap: .4rem; }
.reveal input { flex: 1; min-width: 0; }
.reveal button {
  margin: 0; padding: .5rem .7rem; flex: 0 0 auto;
  font-size: .82rem; font-weight: 400;
  background: var(--navy-soft); color: var(--navy);
}
.reveal button:hover { background: var(--gold-soft); }

/* A request in flight. Every api() call sets this, so nothing double-submits and
   a weak connection looks like something rather than nothing. */
button[aria-busy="true"] { opacity: .6; cursor: progress; }
button:disabled { opacity: .55; cursor: not-allowed; }

/* One list item. Replaces <fieldset> used as a card — a fieldset with no legend
   is a form group announced as one, and it made a request awaiting your decision
   look exactly like a settled record from March. The left edge carries the state. */
.item {
  margin-top: .6rem; padding: .75rem .9rem; background: var(--white);
  border: 1px solid var(--rule); border-left: 3px solid var(--rule); border-radius: .5rem;
}
.item > p:first-child { margin-top: 0; }
.item > :last-child { margin-bottom: 0; }
.item.act  { border-left-color: var(--gold); }     /* needs a decision from you */
.item.wait { border-left-color: var(--info); }     /* waiting on somebody else */
.item.late { border-left-color: var(--danger); }   /* overdue, or refused */
.item.done { border-left-color: var(--ok); }       /* settled */
.item.off  { background: transparent; }            /* dormant: cancelled, history */

/* Status word. Same four meanings as the item edges. */
.state {
  display: inline-block; padding: .14rem .55rem; border-radius: 1rem;
  font-size: .74rem; font-weight: 700; white-space: nowrap;
  background: var(--navy-soft); color: var(--ink-soft);
}
.state.act  { background: var(--gold-soft);   color: var(--gold-ink); }
.state.wait { background: var(--info-soft);   color: var(--info); }
.state.late { background: var(--danger-soft); color: var(--danger); }
.state.done { background: var(--ok-soft);     color: var(--ok); }

/* Count on a tab. Hidden when the queue is empty rather than reading "0". */
.badge {
  display: inline-block; min-width: 1.35rem; margin-left: .35rem;
  padding: .05rem .4rem; border-radius: 1rem; text-align: center;
  background: var(--gold); color: var(--white); font-size: .72rem; font-weight: 700;
}
.badge:empty { display: none; }
.badge.dot { background: var(--danger); min-width: 0; padding: 0 .3rem; }

/* An empty list says what will appear there, so a first week does not look broken. */
.empty {
  margin: .6rem 0; padding: .9rem; border: 1px dashed var(--rule); border-radius: .5rem;
  color: var(--ink-soft); font-size: .9rem; text-align: center;
}

/* A validation message on the field it belongs to. The server decides what is
   wrong, so this is the only place the page renders a rule. */
.err-field {
  margin: -.55rem 0 .7rem; font-size: .8rem; font-weight: 700; color: var(--danger);
}

/* A small either/or. Both options stay visible, and they are radios rather than
   checkboxes because exactly one of them is true. */
.choice { display: flex; gap: 1.1rem; flex-wrap: wrap; margin: .1rem 0 .2rem; }
.choice label { display: flex; align-items: center; gap: .35rem; margin: 0; font-weight: 400; }
.choice input { width: auto; }
