/* Jubilee admin.
 *
 * Written for someone who uses this a few times a year and needs to relearn it
 * every time: 18px base, Atkinson Hyperlegible (designed by the Braille
 * Institute for low-vision readers), AAA contrast on text, 48px targets, and
 * status that is always a word as well as a colour.
 *
 * Spacing is a scale, not ad-hoc values, so pages stay consistent as they grow.
 */

@font-face {
  font-family: "Atkinson Hyperlegible";
  src: url("/static/fonts/atkinson-400.woff2") format("woff2");
  font-weight: 400; font-style: normal; font-display: swap;
}
@font-face {
  font-family: "Atkinson Hyperlegible";
  src: url("/static/fonts/atkinson-700.woff2") format("woff2");
  font-weight: 700; font-style: normal; font-display: swap;
}

:root {
  --ink: #1a2233;
  /* Every text colour here is >= 7:1 (WCAG AAA) on both white panels and
     the grey page ground, measured, not estimated. */
  --ink-2: #475164;         /* secondary text: 8.3:1 on white */
  --paper: #ffffff;
  --ground: #eef1f5;        /* page background behind panels */
  --rule: #cfd6e0;
  --blue: #1e4ca2;          /* 7.5:1 on white */
  --blue-deep: #173d85;
  /* Lightened from #e8eefa: blue text on it measured 6.91:1, just under the
     7:1 this project holds itself to. Used for button hover, notices and the
     report card highlight, so the shortfall was everywhere at once. */
  --blue-wash: #edf2fc;
  --green: #196534;         /* 6.7:1 */
  --green-wash: #e6f4ea;
  --amber: #7e4400;         /* 7.0:1 as text */
  --amber-wash: #fff4e0;
  --red: #a4201a;           /* 7.4:1 */
  --red-wash: #fdecea;

  --s1: .25rem; --s2: .5rem; --s3: .75rem; --s4: 1rem;
  --s5: 1.5rem; --s6: 2rem; --s7: 3rem;

  --radius: 8px;
  --target: 48px;
  --font: "Atkinson Hyperlegible", ui-sans-serif, system-ui, -apple-system,
          "Segoe UI", Roboto, sans-serif;
}

/* Text size setting. Everything is in rem, so this scales the whole screen. */
html { font-size: 112.5%; }            /* 18px */
html[data-size="large"] { font-size: 125%; }    /* 20px */
html[data-size="larger"] { font-size: 140%; }   /* 22.4px */

*, *::before, *::after { box-sizing: border-box; }
[hidden] { display: none !important; }
body {
  margin: 0; font-family: var(--font); color: var(--ink);
  background: var(--ground); line-height: 1.55;
  -webkit-font-smoothing: antialiased;
}
h1, h2, h3, p, ul, ol { margin: 0; }
img { max-width: 100%; }

/* ---------- skip link ---------- */
.skip {
  position: absolute; left: var(--s4); top: -4rem; z-index: 100;
  background: var(--ink); color: #fff; padding: var(--s3) var(--s4);
  border-radius: var(--radius); font-weight: 700;
}
.skip:focus { top: var(--s4); }

/* ---------- focus: always visible, never removed ---------- */
:focus-visible {
  outline: 3px solid var(--blue); outline-offset: 3px; border-radius: 4px;
}

/* ---------- shell ---------- */
.shell { display: grid; grid-template-columns: 17rem 1fr; min-height: 100dvh; }

.side {
  background: var(--ink); color: #fff; padding: var(--s4);
  display: flex; flex-direction: column; gap: var(--s3);
  position: sticky; top: 0; height: 100dvh; overflow-y: auto;
}

.brand { display: flex; flex-direction: column; padding: 0 var(--s2); }
.brand strong { font-size: 1.15rem; line-height: 1.25; }
.brand span { color: #b8c2d4; font-size: .85rem; }

.navgroup h2 {
  font-size: .8rem; font-weight: 700; color: #b8c2d4;
  padding: 0 var(--s2); margin-bottom: var(--s1);
}
.navgroup ul { list-style: none; padding: 0; display: grid; gap: 2px; }
.navgroup a {
  display: flex; align-items: center; min-height: 44px;
  padding: 0 var(--s3); border-radius: var(--radius);
  color: #e8ecf3; text-decoration: none; font-size: 1rem;
}
.navgroup a:hover { background: rgba(255,255,255,.08); }
.navgroup a[aria-current="page"] {
  background: #fff; color: var(--ink); font-weight: 700;
}





.top { display: none; }

/* Account controls live above the content, not in the sidebar. At common
   small-laptop heights a sidebar footer pushed whole nav sections below the
   fold -- navigation matters more than the sign-out link. */
.utility {
  display: flex; align-items: center; justify-content: flex-end; flex-wrap: wrap;
  gap: var(--s1) var(--s3); margin: calc(var(--s4) * -1) 0 var(--s5);
  font-size: .95rem;
}
.utility .who { color: var(--ink-2); margin-right: auto; min-width: 0;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis; flex: 1 1 12rem; }
.utility a, .utility button {
  color: var(--blue); background: none; border: 0; font: inherit; cursor: pointer;
  text-decoration: underline; min-height: 44px; padding: 0 var(--s1);
  display: inline-flex; align-items: center;
}
.main { padding: var(--s6) var(--s6) var(--s7); min-width: 0; }
.content { max-width: 46rem; }

/* ---------- page head ---------- */
.pagehead { margin-bottom: var(--s6); }
.pagehead h1 { font-size: 2rem; line-height: 1.2; margin-bottom: var(--s2); }
.pagehead p { color: var(--ink-2); font-size: 1.05rem; max-width: 38rem; }

/* ---------- panels ----------
 * Panels group one task. They are not decoration: one panel, one job. */
.panel {
  min-width: 0;
  background: var(--paper); border: 1px solid var(--rule);
  border-radius: var(--radius); padding: var(--s5); margin-bottom: var(--s5);
}
.panel > h2 { font-size: 1.3rem; margin-bottom: var(--s2); }
.panel > .lede { color: var(--ink-2); margin-bottom: var(--s4); }

/* ---------- forms ---------- */
.field { display: grid; gap: var(--s2); margin-bottom: var(--s4); }
/* Grid items default to min-width:auto, and date/time inputs carry a built-in
   minimum width -- together they pushed the Social form off a phone screen. */
.field > * { min-width: 0; }
.pair > * { min-width: 0; }
.field label { font-weight: 700; font-size: 1rem; }
.field .hint { color: var(--ink-2); font-size: .95rem; margin-top: calc(var(--s1) * -1); }
.field input, .field select, .field textarea {
  font: inherit; font-size: 1rem; color: var(--ink); background: #fff;
  border: 2px solid #8a94a6; border-radius: var(--radius);
  padding: var(--s3); min-height: var(--target); width: 100%;
}
.field textarea { min-height: 7rem; resize: vertical; }
.field input:focus, .field select:focus, .field textarea:focus {
  border-color: var(--blue); outline: 3px solid var(--blue-wash); outline-offset: 0;
}
.field input[aria-invalid="true"] { border-color: var(--red); }

.pair { display: grid; grid-template-columns: 1fr 1fr; gap: var(--s4); }

.check {
  display: flex; gap: var(--s3); align-items: flex-start; cursor: pointer;
  min-height: var(--target); padding: var(--s2) 0; font-size: 1rem;
}
.check input { width: 1.4rem; height: 1.4rem; margin-top: .15rem; flex: 0 0 auto;
  accent-color: var(--blue); }

/* ---------- buttons ----------
 * Three kinds only, so meaning is learnable: go, quiet, and destroy. */
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: var(--s2);
  min-height: var(--target); padding: 0 var(--s5); border-radius: var(--radius);
  font: inherit; font-size: 1rem; font-weight: 700; cursor: pointer;
  border: 2px solid transparent; text-decoration: none; max-width: 100%;
  text-align: center;
}
/* Labels stay on one line where there is room. At the largest text size on a
   phone, "Put message on the map" was 345px on a 320px screen and dragged the
   whole panel sideways with it, so below that width they wrap. */
@media (min-width: 641px) { .btn { white-space: nowrap; } }
@media (max-width: 640px) { .btn { padding-top: var(--s2); padding-bottom: var(--s2); } }
.btn-go { background: var(--blue); color: #fff; }
.btn-go:hover { background: var(--blue-deep); }
.btn-quiet { background: #fff; color: var(--blue); border-color: var(--blue); }
.btn-quiet:hover { background: var(--blue-wash); }
.btn-stop { background: #fff; color: var(--red); border-color: var(--red); }
.btn-stop:hover { background: var(--red-wash); }
.btn[disabled] { opacity: .55; cursor: not-allowed; }
.btn-small { min-height: 40px; padding: 0 var(--s4); font-size: .95rem; }

.actions { display: flex; gap: var(--s3); flex-wrap: wrap; margin-top: var(--s4); }

/* ---------- messages ---------- */
.notice {
  border-radius: var(--radius); padding: var(--s3) var(--s4);
  border-left: 5px solid; margin-bottom: var(--s4); font-size: 1rem;
}
.notice:empty { display: none; }
.notice.ok   { background: var(--green-wash); border-color: var(--green); color: #0f4222; }
.notice.bad  { background: var(--red-wash);   border-color: var(--red);   color: #6b120e; }
.notice.warn { background: var(--amber-wash); border-color: #c77700;      color: #5c3100; }
.notice.info { background: var(--blue-wash);  border-color: var(--blue);  color: #11306a; }

/* ---------- status: word + colour, never colour alone ---------- */
.status {
  display: inline-flex; align-items: center; gap: var(--s2);
  font-weight: 700; font-size: .95rem;
}
.status::before {
  content: ""; width: .7rem; height: .7rem; border-radius: 50%; flex: 0 0 auto;
}
.status.ok   { color: var(--green); } .status.ok::before   { background: var(--green); }
.status.warn { color: var(--amber); } .status.warn::before { background: #c77700; }
.status.bad  { color: var(--red); }   .status.bad::before  { background: var(--red); }
.status.off  { color: var(--ink-2); } .status.off::before  { background: #8a94a6; }

/* ---------- lists of things ---------- */
.rows { list-style: none; padding: 0; border-top: 1px solid var(--rule); }
.rows > li {
  display: flex; gap: var(--s4); align-items: center; justify-content: space-between;
  padding: var(--s4) 0; border-bottom: 1px solid var(--rule); flex-wrap: wrap;
}
.rows .what { min-width: 0; flex: 1 1 16rem; overflow-wrap: anywhere; }
.rows .what strong { display: block; font-size: 1.05rem; }
.rows .what span { color: var(--ink-2); font-size: .95rem; }
.rows .do { display: flex; gap: var(--s2); flex-wrap: wrap; }
.empty { color: var(--ink-2); padding: var(--s4) 0; }

/* ---------- secret reveal (shown once) ---------- */
.secret {
  background: var(--amber-wash); border: 2px solid #c77700; border-radius: var(--radius);
  padding: var(--s4); margin-top: var(--s4);
}
.secret h3 { font-size: 1.1rem; margin-bottom: var(--s2); }
.secret dl { display: grid; grid-template-columns: max-content 1fr; gap: var(--s2) var(--s4);
  margin: var(--s3) 0 0; }
.secret dt { font-weight: 700; }
.secret dd { margin: 0; font-family: ui-monospace, "Cascadia Mono", Menlo, monospace;
  font-size: 1rem; word-break: break-all; }

/* ---------- small screens ---------- */
@media (max-width: 860px) {
  .shell { grid-template-columns: 1fr; }
  .top {
    display: flex; align-items: center; justify-content: space-between;
    background: var(--ink); color: #fff; padding: var(--s3) var(--s4);
    position: sticky; top: 0; z-index: 70;
    border-bottom: 1px solid rgba(255,255,255,.15);
  }
  .top strong { font-size: 1.1rem; }
  .top button {
    font: inherit; font-weight: 700; color: var(--ink); background: #fff;
    border: 0; border-radius: var(--radius); min-height: var(--target); padding: 0 var(--s4);
    white-space: nowrap;
  }
  .side { display: none; position: fixed; inset: 0; z-index: 60; height: 100dvh;
          padding-top: calc(var(--target) + var(--s5) + var(--s3)); }
  .side .brand { display: none; }
  .side.open { display: flex; }
  .main { padding: var(--s5) var(--s4) var(--s7); }
  .utility { margin-top: 0; justify-content: flex-start; }
  .utility .who { flex-basis: 100%; }
  .pagehead h1 { font-size: 1.6rem; }
  .pair { grid-template-columns: 1fr; }
  .actions .btn { flex: 1 1 100%; }
}

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

/* ---------- "?" help ----------
 * Opens on hover, tap, click and keyboard focus. Hover alone fails for this
 * audience: tablets cannot hover, keyboard users never trigger it, and a tip
 * that vanishes when the mouse wobbles is hard for unsteady hands. A click or
 * tap pins it open until dismissed. */
.hq { position: relative; display: inline-flex; vertical-align: middle; margin-left: .35rem; }
.hq-btn {
  position: relative; width: 1.55rem; height: 1.55rem; border-radius: 50%;
  border: 2px solid var(--blue); background: #fff; color: var(--blue);
  font: inherit; font-size: .85rem; font-weight: 700; line-height: 1;
  cursor: pointer; display: grid; place-items: center; padding: 0;
}
/* Visual size stays small next to a label; the hit area is 44px. */
.hq-btn::before { content: ""; position: absolute; inset: -.55rem; }
.hq-btn:hover, .hq-btn[aria-expanded="true"] { background: var(--blue); color: #fff; }
/* Always fixed and out of the page's layout. Revealed in place as an absolutely
   positioned box for even one frame, it made the browser jump the page
   by several hundred pixels near the bottom of long pages. */
.hq-pop {
  position: fixed; top: 0; left: 0; z-index: 1100;
  width: min(22rem, 82vw); background: var(--ink); color: #fff;
  border-radius: var(--radius); padding: var(--s3) var(--s4); font-size: .95rem;
  font-weight: 400; line-height: 1.5; text-align: left; white-space: normal;
  box-shadow: 0 8px 28px rgba(20,30,50,.28);
}
.hq-pop strong { display: block; margin-bottom: var(--s1); font-size: 1rem; }
.hq-pop a { color: #cfe0ff; display: inline-block; margin-top: var(--s2);
            min-height: 32px; line-height: 32px; }
.hq-pop .hq-x { position: absolute; top: .25rem; right: .25rem; background: none;
  border: 0; color: #b8c2d4; font: inherit; font-size: 1.2rem; cursor: pointer;
  width: 36px; height: 36px; border-radius: 6px; }
.hq-pop .hq-x:hover { color: #fff; background: rgba(255,255,255,.1); }
.panel > h2 .hq, .field label .hq, .pagehead h1 .hq { margin-left: .5rem; }

/* ---------- wizards ----------
 * One task broken into short steps. The steps are a real sequence, so they are
 * numbered, and progress is always visible. */
.wiz-progress { list-style: none; padding: 0; margin: 0 0 var(--s5);
  display: flex; gap: var(--s2); flex-wrap: wrap; counter-reset: wz; }
.wiz-progress li { counter-increment: wz; display: flex; align-items: center; gap: var(--s2);
  color: var(--ink-2); font-size: .95rem; padding: var(--s1) var(--s3) var(--s1) var(--s1);
  border-radius: 999px; background: #fff; border: 1px solid var(--rule); }
.wiz-progress li::before { content: counter(wz); width: 1.7rem; height: 1.7rem;
  border-radius: 50%; display: grid; place-items: center; font-weight: 700;
  background: var(--ground); color: var(--ink-2); }
.wiz-progress li.here { color: var(--ink); font-weight: 700; border-color: var(--blue); }
.wiz-progress li.here::before { background: var(--blue); color: #fff; }
.wiz-progress li.done::before { content: "✓"; background: var(--green); color: #fff; }
.wiz-step h2 { font-size: 1.5rem; margin-bottom: var(--s2); }
.wiz-step h2:focus { outline: none; }
.wiz-step > .lede { color: var(--ink-2); font-size: 1.05rem; margin-bottom: var(--s5);
  max-width: 38rem; }
.wiz-nav { display: flex; justify-content: space-between; gap: var(--s3);
  margin-top: var(--s5); padding-top: var(--s4); border-top: 1px solid var(--rule); }
.wiz-nav .btn-go { min-width: 9rem; }
.summary { display: grid; grid-template-columns: max-content 1fr; gap: var(--s3) var(--s5);
  margin: 0; }
.summary dt { font-weight: 700; }
.summary dd { margin: 0; }
.big-ok { text-align: center; padding: var(--s6) var(--s4); }
.big-ok .tick { width: 4.5rem; height: 4.5rem; border-radius: 50%; margin: 0 auto var(--s4);
  background: var(--green); color: #fff; display: grid; place-items: center; font-size: 2.2rem; }
.big-ok h2 { font-size: 1.7rem; margin-bottom: var(--s2); }
.waiting { display: flex; gap: var(--s4); align-items: center; padding: var(--s4);
  background: var(--blue-wash); border-radius: var(--radius); }
.spin { width: 1.8rem; height: 1.8rem; border-radius: 50%; flex: 0 0 auto;
  border: 3px solid var(--blue); border-right-color: transparent;
  animation: spin 1s linear infinite; }
@keyframes spin { to { transform: rotate(360deg); } }
.storelinks { display: flex; gap: var(--s3); flex-wrap: wrap; margin: var(--s3) 0; }
@media (max-width: 640px) {
  .summary { grid-template-columns: 1fr; gap: var(--s1); }
  .summary dd { margin-bottom: var(--s3); }
  .wiz-progress li { font-size: 0; padding: var(--s1); }
  .wiz-progress li.here { font-size: .95rem; padding-right: var(--s3); }
}

/* Leaflet stacks its panes at z-index 400-1000 in whatever stacking context it
   lands in. Isolate the map so those layers can never cover the page around it
   -- the help pop-ups sat underneath the map before this. */
.leaflet-container { isolation: isolate; }

/* Zone editor corner handles: a 24px target (WCAG 2.2 AA, 2.5.8) holding a
   12px visible square, so the map stays readable while the corners are
   easier to grab. */
.vtx { background: transparent !important; border: 0 !important;
       display: grid; place-items: center; cursor: move; }
.vtx::after { content: ""; width: 12px; height: 12px; background: #fff;
              border: 3px solid #a4201a; border-radius: 3px; box-sizing: border-box; }
.vtx:focus-visible::after { outline: 3px solid var(--blue); outline-offset: 2px; }

/* Route stops: name, then Up / Down / Remove. On a narrow screen at large text
   they cannot share a line, so the buttons drop below the name. */
@media (max-width: 640px) {
  .stops li { flex-wrap: wrap; }
  .stops li .nm { flex: 1 1 60%; }
  .stops li .btn { flex: 1 1 0; }
}

/* Padding is in rem, so it grows with the text-size setting. On a phone at the
   largest size that left the words about 200px of a 320px screen. Fixed pixel
   padding on small screens gives the room back to the text. */
@media (max-width: 640px) {
  .main { padding-left: 12px; padding-right: 12px; }
  .panel { padding: 16px 14px; }
  .verdict { padding: 16px 14px 16px 26px; }
}

/* File pickers styled as buttons. The real input stays in the page (clipped,
   not moved off-screen), so it still takes keyboard focus -- and the visible
   button shows that focus. Moving it off-screen would put the focus ring
   somewhere nobody can see it. */
.fileinput { position: absolute; width: 1px; height: 1px; opacity: 0;
             overflow: hidden; clip-path: inset(50%); white-space: nowrap; }
label:has(> .fileinput:focus-visible),
.file-row:has(.fileinput:focus-visible) > label {
  outline: 3px solid var(--blue); outline-offset: 3px; }

/* Shown to Jubilee staff inside a city's admin. */
.operatorbar { background: #3b0764; color: #fff; padding: .7rem 1rem; border-radius: var(--radius);
               margin-bottom: 1rem; line-height: 1.5; }
.operatorbar a { color: #fff; font-weight: 700; }

/* Console controls by role. data-needs="support": Administrator and Support.
   data-needs="admin": Administrator only. Hidden until the role is known, so a
   button never flashes up for someone who cannot use it. */
html:not([data-role]) [data-needs] { visibility: hidden; }
html[data-role="platform_viewer"] [data-needs="support"],
html[data-role="platform_viewer"] [data-needs="admin"],
html[data-role="platform_support"] [data-needs="admin"] { display: none !important; }
