:root { color-scheme: light dark; --accent-ink:#fff; --ink:#1d2a33; --muted:#5e6b73; --bg:#f6f8f7; --card:#fff; --line:#dfe5e3; --accent:#1f7a5c;
  /* For the muted text that always lands inside the backdrop band: grey
     enough to stay secondary, dark enough to be read over gum leaves. */
  --muted-on-photo:#3b4a52;
  --chip:#eef2f0; --bar-bg:#e6ebe9; --tag-bg:#e3f1ec; --map-bg:#dfe9ee;
  --error-bg:#fdecea; --error-ink:#8a1f16;
  --warn-bg:#fff7e0;  --warn-ink:#6b4f00;
  --note-bg:#eef4ff;  --note-ink:#1e3a68;
  /* The veil over the backdrop photograph, in the page's own background
     colour. A variable because dark mode needs a DARK veil: laying the
     light one over the photo there would fog it exactly as it fogged the
     iPhone app's light mode. */
  --veil:246,248,247;
  --rubbish:#c8322b; --recycling:#e0b000; --organics:#3a9a3f; --glass:#7b4fb0; --hard_waste:#555; --other:#8a8f93; }
/* Dark mode, by redefining the palette and nothing else. Every surface on
   the page already reads one of these, which is why this block is short:
   the work was moving .error, .bin, .tag and the rest off their literal
   colours and onto variables above.

   The accent lifts from #1f7a5c to #55c79c because a green dark enough to
   read as a button on white is nearly invisible on near-black, and the
   button's own text flips to dark for the same reason. The bin colours are
   left alone: red, yellow and green are the lids themselves and mean the
   same in any theme, and they sit on their own chips rather than on the
   page. */
@media (prefers-color-scheme: dark) {
  :root {
    --ink:#e6ece9; --muted:#9aaaa4; --bg:#101714; --card:#19221e; --line:#2a352f;
    --accent:#55c79c; --accent-ink:#06120d;
    --muted-on-photo:#c3d2cb;
    --chip:#232e29; --bar-bg:#232e29; --tag-bg:#1c3a30; --map-bg:#16211d;
    --error-bg:#3a1a17; --error-ink:#ff9a8f;
    --warn-bg:#332a10;  --warn-ink:#f0cd7a;
    --note-bg:#152238;  --note-ink:#a8c6f5;
    --veil:16,23,20;
  }
  /* The photograph is already dark; veiling it as hard as the light page
     does would leave mud. Same number the iPhone app settled on. */
  body::before { background-blend-mode: normal; }
  /* Form controls do not inherit the palette, and a white field on a dark
     page is a torch. */
  input, select, textarea { background:var(--card); color:var(--ink); border-color:var(--line); }
  input::placeholder { color:var(--muted); }
  /* Tell the browser, so scrollbars and the address bar match. */
  :root { color-scheme: dark; }
}

* { box-sizing: border-box; }
body { margin:0; font: 16px/1.5 -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif; color:var(--ink); background:var(--bg); }
/* The same photograph the iPhone app puts behind its top screen: gum
   leaves on weathered wood, April Pethybridge on Unsplash, free under the
   Unsplash Licence. Credited in the footer beside the ABS and G-NAF lines,
   which is the courtesy that licence asks for.

   Treated as texture rather than picture, and the treatment is the app's,
   arrived at there: veiled at 0.42 in the page's own background colour,
   which is far LESS veil than feels natural - white over a dark photograph
   drains it rather than lightening it, so bleaching it towards the page
   gives fog, not light. Faded out over its own height with a mask so the
   content below sits on the ordinary background and reads as it always
   did.

   The filename is cache-busted by nothing: /static is served immutable for
   a year and this URL sits inside the stylesheet rather than going through
   assetURL. Changing the picture means changing the filename. */
body::before {
  content:""; position:absolute; top:0; left:0; right:0; z-index:-1;
  height: min(42vh, 380px);
  background:
    linear-gradient(rgba(var(--veil),.52), rgba(var(--veil),.52)),
    url("/static/backdrop.jpg") center/cover no-repeat;
  -webkit-mask-image: linear-gradient(to bottom, #000 0, rgba(0,0,0,.85) 45%, transparent 100%);
  mask-image: linear-gradient(to bottom, #000 0, rgba(0,0,0,.85) 45%, transparent 100%);
}
/* Transparent so the photograph runs behind it, as the app's navigation
   bar does. The rule below it does the separating that the border did. */
.top { display:flex; align-items:center; justify-content:space-between; padding:14px 20px; }
/* The bins themselves, beside the name. width/height are on the img as well
   as here so the header does not reflow when it loads. */
/* No gap on the flex container: "which" and <span>bins</span> are two flex
   items, so a gap meant to separate the icon from the name also splits the
   name down the middle. The space belongs to the icon, so the icon carries
   it. */
.brand { display:inline-flex; align-items:center;
  font-weight:700; font-size:20px; color:var(--ink); text-decoration:none; letter-spacing:-.01em; }
.brand img { width:28px; height:28px; border-radius:6px; display:block; margin-right:9px; }
.brand span { color:var(--accent); }
nav a { margin-left:18px; color:var(--ink); text-decoration:none; white-space:nowrap; }
nav a:hover { color:var(--ink); }
main { max-width: 760px; margin: 0 auto; padding: 32px 20px 60px; }
h1 { font-size: 30px; line-height:1.2; margin: 0 0 8px; letter-spacing:-.02em; }
h2 { font-size: 18px; margin: 0 0 8px; }
.lede { font-size: 18px; color: var(--muted); margin: 0 0 24px; }
/* The two lines that always land inside the backdrop band: the home
   page's lede, and the breadcrumb at the top of every inner page. */
.hero .lede, .crumb { color: var(--muted-on-photo); }
.search { display:grid; gap:8px; background:var(--card); border:1px solid var(--line); border-radius:12px; padding:20px; }
.search label { font-size:13px; color:var(--muted); font-weight:600; text-transform:uppercase; letter-spacing:.04em; }
.search input { font: inherit; padding:12px 14px; border:1px solid var(--line); border-radius:8px; }
.search button { margin-top:8px; font:inherit; font-weight:600; padding:12px; border:0; border-radius:8px; background:var(--accent); color:var(--accent-ink); cursor:pointer; }
.muted { color: var(--muted); }
/* The App Store badge row under the search box. Apple's black badge with
   its grey keyline, which reads on both the light page and the dark one,
   so there is no second badge to swap in. Height-matched to a line of text
   rather than scaled up: it is a way in, not an advertisement. */
.appstore { display:flex; flex-wrap:wrap; align-items:center; gap:8px 16px; margin:16px 0 8px; }
.appstore img { display:block; width:120px; height:40px; }
.hero .appstore .muted { color: var(--muted-on-photo); }
.small { font-size:13px; margin:0; }
.error { background:var(--error-bg); color:var(--error-ink); padding:10px 14px; border-radius:8px; }
.hint { background:var(--warn-bg); color:var(--warn-ink); padding:10px 14px; border-radius:8px; }
.unconfirmed { background:var(--warn-bg); color:var(--warn-ink); padding:10px 12px; border-radius:8px; margin:12px 0 0; font-size:13px; line-height:1.45; }
/* A date the council itself published in place of the one the pattern
   gives. Not a warning - the opposite - so it is read as information
   rather than as the amber .unconfirmed above it. */
.moved { background:var(--note-bg); color:var(--note-ink); padding:10px 12px; border-radius:8px; margin:12px 0 0; font-size:13px; line-height:1.45; }
.crumb { color:var(--muted); margin:0 0 12px; }
.matches { list-style:none; padding:0; margin:0; display:grid; gap:8px; }
.matches a { display:block; padding:12px 14px; background:var(--card); border:1px solid var(--line); border-radius:8px; color:var(--ink); text-decoration:none; }
.matches a:hover { border-color: var(--accent); }
.week { background:var(--card); border:1px solid var(--line); border-radius:12px; padding:16px 18px; margin:0 0 14px; }
.week .when { color: var(--muted); font-weight:400; margin-left:8px; }
.bins { list-style:none; padding:0; margin:0; display:flex; flex-wrap:wrap; gap:8px; }
.bin { display:flex; align-items:center; gap:8px; padding:8px 12px; border-radius:999px; background:var(--chip); font-weight:600; }
.bin .dot { width:14px; height:14px; border-radius:50%; background:var(--other); }
.bin.rubbish .dot { background:var(--rubbish); } .bin.recycling .dot { background:var(--recycling); }
.bin.organics .dot { background:var(--organics); } .bin.glass .dot { background:var(--glass); } .bin.hard_waste .dot { background:var(--hard_waste); }
table { width:100%; border-collapse:collapse; background:var(--card); border:1px solid var(--line); border-radius:12px; margin:0 0 20px; font-size:15px; }
th, td { text-align:left; padding:8px 10px; border-bottom:1px solid var(--line); vertical-align:top; }
th { font-size:12px; text-transform:uppercase; letter-spacing:.04em; color:var(--muted); }
.bar { height:8px; background:var(--bar-bg); border-radius:4px; min-width:80px; } .bar span { display:block; height:8px; background:var(--accent); border-radius:4px; }
/* A pill that wraps is not a pill: the 999px radius turns two lines into a
   tall lozenge with the text floating inside it, which is what "Published
   timetable" did in the coverage table on a phone while "Address lookup"
   sat neatly on one line beside it. Pills do not wrap. The label itself is
   not shortened, because the paragraph above the table explains each one by
   name and the two have to match. */
.tag { display:inline-block; white-space:nowrap; font-size:12px; padding:2px 8px; border-radius:999px; background:var(--tag-bg); color:var(--accent); margin-right:4px; }
.tag.none { background:var(--chip); color:var(--muted); }
.ok { color: var(--organics); font-weight:600; } .bad { color: var(--rubbish); font-weight:600; }
footer { max-width:760px; margin:0 auto; padding:24px 20px 40px; color:var(--muted); font-size:13px;
  border-top:1px solid var(--line); }
/* The links first and on their own line, so the privacy policy is somewhere
   a person can find it rather than a word inside a paragraph about the ABS.
   Wraps to two rows on a phone rather than shrinking. */
.footlinks { display:flex; flex-wrap:wrap; gap:8px 20px; margin:0 0 14px; }
.footlinks a { color:var(--ink); font-weight:600; text-decoration:none; }
.footlinks a:hover { text-decoration:underline; }
footer p { margin:0 0 10px; }
/* The lines down here that are a warning rather than a reference, and the
   only ones that stay out from behind the disclosure. */
.caveat { color:var(--ink); max-width:62ch; }
/* Provenance and licences, present on every page and one keystroke away
   rather than three paragraphs of small print under the search box. A
   <details> and not a modal: no script, it prints, it is keyboard
   reachable, and find-in-page reaches the text inside it. */
.about { margin: 2px 0 0; }
.about summary { color:var(--muted); cursor:pointer; padding:2px 0; width:max-content; }
.about summary:hover { color:var(--ink); }
.about p { margin:10px 0 0; }
/* The same disclosure above a table rather than under a page, so it needs
   room beneath it before the data starts. */
.legend { margin: 0 0 18px; }
/* One state, openable. The summary carries the state's own numbers and its
   bar, so the page opens as eight lines that each answer "how much of this
   state is covered" without opening anything. */
.state { border-top:1px solid var(--line); }
.state:last-of-type { border-bottom:1px solid var(--line); }
/* display:flex on a summary drops the browser's own disclosure triangle, so
   the row stops looking like something you can open. Put one back, and turn
   it, rather than leaving eight lines that give no sign they do anything. */
.state > summary { display:flex; align-items:center; gap:10px; padding:12px 2px; cursor:pointer; }
.state > summary::marker, .state > summary::-webkit-details-marker { content:""; display:none; }
.state > summary::before { content:"\25B8"; color:var(--muted); font-size:12px; width:1em; }
.state[open] > summary::before { content:"\25BE"; }
.state > summary:hover { background:var(--chip); }
.state .st { font-weight:700; min-width:3.2em; }
.state summary .bar { margin-left:auto; width:120px; min-width:0; flex:none; }
.state[open] > summary { border-bottom:1px solid var(--line); }
.state .tablewrap { margin:0 0 6px; }
@media (max-width: 600px) {
  .state summary .bar { width:64px; }
}
.credits { font-size:12px; opacity:.85; }
/* A wide table on a narrow screen. Letting it scroll sideways inside its
   own box is the one option that neither squeezes a column to nothing nor
   pushes the whole page sideways - and the coverage table was doing the
   second, with its "working?" column cut off at the right edge of the
   phone. The wrapper is only ever scrolled when the table does not fit. */
.tablewrap { overflow-x:auto; -webkit-overflow-scrolling:touch; margin:0 0 20px; }
.tablewrap table { margin-bottom:0; }
.tablewrap .councils { min-width:520px; }

@media (max-width: 600px) {
  h1 { font-size:24px; }
  main { padding: 20px 14px 40px; }
  .councils td:nth-child(4) { font-size:13px; }
  /* The header was one flex row of brand-then-nav, which on a phone ran the
     four links into the wordmark and broke "Sign in" across two lines - the
     "in" landing under the brand on its own. Two rows instead: the name,
     then the links spread beneath it. Nothing is smaller, nothing is
     hidden behind a hamburger, and the tap targets grow rather than shrink. */
  .top { flex-wrap: wrap; padding: 12px 14px 10px; }
  .brand { font-size: 19px; }
  .top nav { width: 100%; display: flex; flex-wrap: wrap; gap: 4px 18px; margin-top: 10px; }
  .top nav a { margin-left: 0; padding: 2px 0; }
}
.mapwrap { max-width: none; }
#map { height: 70vh; min-height: 420px; border: 1px solid var(--line); border-radius: 12px; background: var(--map-bg); }
.legend { color: var(--muted); font-size: 14px; }
.legend .sw { display:inline-block; width:14px; height:14px; border-radius:3px; vertical-align:-2px; margin: 0 4px 0 12px; }
.legend .sw.ok { background:#1f7a5c; } .legend .sw.broken { background:#c8322b; } .legend .sw.unchecked { background:#e0b000; } .legend .sw.none { background:#b8c0bd; }
.narrow { max-width: 440px; }
.save { display:flex; gap:8px; margin: 8px 0 16px; }
.save input { flex:1; font:inherit; padding:10px 12px; border:1px solid var(--line); border-radius:8px; }
.save button, .location button { font:inherit; font-weight:600; padding:10px 14px; border:0; border-radius:8px; background:var(--accent); color:#fff; cursor:pointer; }
.location { background:var(--card); border:1px solid var(--line); border-radius:12px; padding:16px 18px; margin:0 0 14px; }
.location .check { display:block; margin: 6px 0; }
.location .row { display:flex; gap:8px; margin-top:10px; }
.location .row input { flex:1; font:inherit; padding:8px 12px; border:1px solid var(--line); border-radius:8px; }
.location button.danger { background:#eee; color:var(--rubbish); }
form.inline { display:inline; } button.link { background:none; border:0; padding:0; color:var(--accent); font:inherit; cursor:pointer; text-decoration:underline; }
.advanced { margin-top: 6px; } .advanced summary { color: var(--muted); font-size: 13px; cursor: pointer; } .advanced label { margin-top: 8px; display:block; }

/* Address suggestions under the search box. The wrapper is positioned so
   the list can overlay what follows rather than pushing the page down as
   the user types. */
.suggest-wrap { position:relative; }
.suggest { position:absolute; z-index:20; top:calc(100% + 4px); left:0; right:0;
  list-style:none; margin:0; padding:4px; max-height:280px; overflow-y:auto;
  background:var(--card); border:1px solid var(--line); border-radius:8px;
  box-shadow:0 8px 24px rgba(29,42,51,.12); }
.suggest li { padding:10px 12px; border-radius:6px; cursor:pointer; }
.suggest li.active, .suggest li:hover { background:#eef2f0; }
/* Not options: they cannot be chosen, hovered or arrowed onto. The
   searching row is a wait; the note is why the list is empty. */
.suggest li.suggest-searching, .suggest li.suggest-note { color:var(--muted); cursor:default; }
.suggest li.suggest-searching { font-style:italic; }
.suggest li.suggest-note { font-size:14px; line-height:1.4; }
.suggest li.suggest-searching:hover, .suggest li.suggest-note:hover { background:transparent; }
/* The same row with a way past the cut: a link-shaped button, then why. */
.suggest li.suggest-more { cursor:default; font-size:14px; line-height:1.4; color:var(--muted); }
.suggest li.suggest-more:hover { background:transparent; }
.suggest li.suggest-more button { font:inherit; font-weight:600; color:var(--accent); background:none; border:0; padding:0; margin-right:8px; cursor:pointer; text-decoration:underline; }

/* The submit button while the bin days are being worked out. The address is
   geocoded and the council read live, so this is seconds, not milliseconds,
   and the button has to say so. Same two marks as the lookup spinner: it
   turns, or for somebody who has asked for less motion, it fades. */
.search.is-working button[type="submit"] { opacity:.85; cursor:progress; }
.search.is-working button[type="submit"]::before {
  content:""; display:inline-block; width:13px; height:13px; margin-right:8px;
  vertical-align:-2px; border:2px solid rgba(255,255,255,.45); border-top-color:#fff;
  border-radius:50%; animation:suggest-spin .7s linear infinite; }
@media (prefers-reduced-motion: reduce) {
  .search.is-working button[type="submit"]::before { animation:suggest-fade 1.2s ease-in-out infinite; }
}

/* The link to a council's own bin page in the coverage table. Quiet: the
   row is about whether we can read it, and this is the way out if we cannot. */
.councils a.own { font-size:13px; color:var(--muted); text-decoration:none; white-space:nowrap; }
.councils a.own:hover { color:var(--accent); text-decoration:underline; }

/* The council we did identify, when its own index did not know the address.
   Same shape as .elsewhere, because it answers the same question - what do I
   do now - for the other half of the cases. */
.identified { background:var(--card); border:1px solid var(--line); border-radius:8px;
  padding:12px 14px; margin:14px 0; }
.identified p { margin:0 0 6px; }
.identified p:last-child { margin-bottom:0; }

/* What was searched for, shown on the results page whether anything matched
   or not. Quiet, because it is context rather than the answer — but present,
   because "no address matched" is unanswerable without it. */
.searched { color: var(--muted); margin: -4px 0 16px; }
.searched strong { color: var(--ink); font-weight: 600; }

/* The spinner while an address lookup is in flight. It sits over the right
   end of the input, inside the same wrapper the list is positioned from.
   The input's own right padding keeps the text from running under it. */
/* The suggester WRAPS the input after the page loads, which takes it out
   of .search's grid: as a grid item it stretched to the form's width, and
   inside a div it fell back to an input's default size of about twenty
   characters. The box got narrower a moment after the page appeared, and
   narrower than the nickname box on the schedule page, which is flex:1
   and had never stopped stretching. Width here rather than on .search
   input, because this is the wrapped case and only the wrapped case. */
.suggest-wrap input { padding-right: 38px; width: 100%; }
.suggest-busy { position:absolute; top:50%; right:12px; width:16px; height:16px; margin-top:-8px;
  pointer-events:none; border:2px solid var(--line); border-top-color:var(--accent);
  border-radius:50%; animation:suggest-spin .7s linear infinite; }
@keyframes suggest-spin { to { transform:rotate(360deg); } }
/* Somebody who has asked for less motion still needs to know we are
   working, so it fades rather than spins. */
@media (prefers-reduced-motion: reduce) {
  .suggest-busy { animation:suggest-fade 1.2s ease-in-out infinite; }
  @keyframes suggest-fade { 0%,100% { opacity:.25; } 50% { opacity:1; } }
}

/* Why we have no bin days for a council, and where its own are. Shown to
   somebody who has just typed their address and got nothing back. */
.elsewhere { background:var(--card); border:1px solid var(--line); border-left:4px solid var(--accent);
  border-radius:8px; padding:12px 16px; margin:0 0 14px; }
.elsewhere p { margin:0 0 6px; }
.elsewhere p:last-child { margin:0; }

/* The privacy policy is the one page here that is mostly prose. Measured
   line length rather than the full 760px, because a paragraph the width of
   a coverage table is hard to read and this is a page somebody reads
   rather than scans. */
.narrow-prose { max-width: 640px; }
.narrow-prose h2 { margin-top: 32px; font-size: 20px; }
.narrow-prose ul { padding-left: 20px; }
.narrow-prose li { margin: 6px 0; }
