/* =============================================================================
   THE GUS BAND — SITE STYLES
   Brand: Heritage Scarlet #BE1D2E · Royal Red #A50E0E · Sovereign Gold #F1C532
   Type:  Noverion Sans. Headings CAPS · sub-heads Title Case · body sentence case
   ============================================================================= */

/* WOFF2, WHICH IS THE SAME THREE FACES AT LESS THAN HALF THE WEIGHT — 108KB of
   TrueType became 48KB, on the first visit to every page. Nothing is lost: the
   format is the web's own, every browser this site supports has read it for
   the best part of a decade, and the .ttf masters are in the folder the fonts
   came from rather than in the site. */
@font-face{font-family:'Noverion';src:url('../fonts/NoverionMedium.woff2') format('woff2');font-weight:500;font-display:swap}
@font-face{font-family:'Noverion';src:url('../fonts/NoverionBold.woff2') format('woff2');font-weight:700;font-display:swap}
@font-face{font-family:'Noverion';src:url('../fonts/NoverionBlack.woff2') format('woff2');font-weight:900;font-display:swap}

:root{
  --scarlet:#BE1D2E; --royal:#A50E0E; --gold:#F1C532;
  --ink:#14100F; --ink-2:#241B1A;
  --paper:#fff; --tint:#FAF6F3; --line:#E6DDD8; --mute:#6B5F5B;
  --wrap:1180px;
  --f:'Noverion',system-ui,-apple-system,"Segoe UI",Roboto,sans-serif;
}

*{box-sizing:border-box}
/* The hidden attribute applies display:none at the lowest priority, so any later
   rule setting display:flex/grid would silently un-hide the element. */
[hidden]{display:none !important}
html{scroll-behavior:smooth}

/* Set on <html> while the biography panel is open, so the page behind can't be
   scrolled under it. On the root rather than on <body>: the root is the element
   that actually scrolls, and locking it leaves the scroll position alone.
   Locking <body> instead is what used to throw the page back to the top every
   time a player was opened. */
/* THE PAGE BEHIND A PANEL, HELD STILL WITHOUT MOVING IT.

   overflow:hidden alone is what made clicking a player jump the page to the
   top. The root is the thing that scrolls; take its ability to scroll away and
   the browser clamps it to zero, and the backdrop is see-through enough that
   you watch it happen.

   So the body is pinned instead, at minus the distance already scrolled — which
   leaves it looking exactly where it was while the root has nothing left to
   scroll. site.js sets --page-y and --bar before adding the class.

   --bar is the width the scrollbar took up. A pinned body has no scrollbar, and
   without putting that width back as padding the whole page slides sideways by
   about fifteen pixels as the panel opens. */
html.dlg-open{overflow:hidden}
html.dlg-open body{position:fixed;top:var(--page-y,0);left:0;right:0;width:100%;
  padding-right:var(--bar,0)}
body{margin:0;font-family:var(--f);font-weight:500;font-size:17px;line-height:1.65;
  color:var(--ink);background:var(--paper);-webkit-font-smoothing:antialiased}
img{max-width:100%;display:block}
a{color:inherit}
h1,h2,h3,h4{margin:0;line-height:1.05;font-weight:900}
/* .ad-welcome-who is the name on the admin's welcome. It is listed here rather
   than given a heading style of its own next to it: the first version had
   Title Case and negative tracking, which is not how this band sets a heading,
   and the only reliable way to keep type in step is to have one declaration of
   it. */
h1,.ad-welcome-who{font-size:clamp(40px,7vw,84px);text-transform:uppercase;
  letter-spacing:.005em}
h2{font-size:clamp(28px,4.2vw,48px);text-transform:uppercase;letter-spacing:.01em}
h3{font-size:22px}
p{margin:0 0 1em}
.wrap{max-width:var(--wrap);margin:0 auto;padding:0 24px}
.vh{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0 0 0 0)}
.skip{position:absolute;left:-9999px;background:var(--gold);color:var(--ink);
  padding:12px 18px;z-index:200;font-weight:700}
.skip:focus{left:12px;top:12px}
:focus-visible{outline:3px solid var(--gold);outline-offset:3px}

/* ---------- type helpers ---------- */
.kicker{font-weight:700;text-transform:uppercase;letter-spacing:.18em;
  font-size:12px;color:var(--scarlet);margin:0 0 12px}
/* The gap under a kicker has to grow with the heading beneath it. A flat 12px
   reads as generous under a 28px heading and cramped under a 48px one, which is
   why "COME AND HEAR US" looked tighter than everything else on the site. The em
   resolves against the heading's own size, so every kicker/heading pair now has
   the same optical gap with nobody tuning it page by page. */
.kicker + h1,.kicker + h2,.kicker + h3,.kicker + p{margin-top:.16em}
.dark .kicker{color:var(--gold)}
.lede{font-size:clamp(17px,1.9vw,21px);line-height:1.6}
.txtlink{font-weight:700;font-size:14px;letter-spacing:.05em;text-decoration:none;
  color:var(--scarlet);border-bottom:2px solid transparent;white-space:nowrap}
.txtlink:hover{border-color:var(--gold)}
.dark .txtlink{color:var(--gold)}

/* ---------- buttons ---------- */
/* ---- THE TRAILING LETTER-SPACE, which affects every label on this site ----
   CSS puts the tracking AFTER the last letter as well as between letters, so a
   letter-spaced word is always carrying an invisible gap on its right. Centre
   that word and you centre the gap with it, which leaves the visible letters
   sitting half the tracking to the LEFT of true centre. Every uppercase label
   here is letter-spaced, so every one of them has it.

   The header lockup already compensates for this in script when it measures the
   band name. These are the CSS equivalents, and there are two, because the fix
   depends on how the text is aligned:

     CENTRED text  ->  text-indent equal to the tracking. The browser centres
                       the line in the width left after the indent and then
                       offsets it by the indent, so the line moves right by half
                       of it — exactly the correction needed.

     LEFT-aligned  ->  take the tracking off the right padding. A shrink-to-fit
     chips            box would otherwise look like it had more air on the right
                       than the left, because it has.

   Both are written in em so they stay correct if the type size changes.        */
.btn{display:inline-flex;align-items:center;justify-content:center;gap:8px;font-weight:700;
  font-size:14px;letter-spacing:.09em;text-indent:.09em;text-transform:uppercase;
  text-decoration:none;
  padding:16px 30px;border:2px solid transparent;border-radius:0;cursor:pointer;
  font-family:inherit;transition:.18s}
.btn-sm{padding:11px 20px;font-size:12.5px}
.btn-gold{background:var(--gold);color:var(--ink);border-color:var(--gold)}
.btn-gold:hover{background:#ffdf5e;border-color:#ffdf5e}
.btn-red{background:var(--scarlet);color:#fff;border-color:var(--scarlet)}
.btn-red:hover{background:var(--royal);border-color:var(--royal)}
/* Royal Red on Heritage Scarlet — the accent doing what it's for, sitting on
   the primary without competing with it. Hovers to ink rather than to a lighter
   red, since there is no red darker than royal to move to. */
.btn-royal{background:var(--royal);color:#fff;border-color:var(--royal)}
.btn-royal:hover{background:var(--ink);border-color:var(--ink)}
.btn-ghost{background:rgba(255,255,255,.07);color:#fff;border-color:rgba(255,255,255,.6)}
.btn-ghost:hover{background:#fff;color:var(--ink);border-color:#fff}
.btn-outline{background:none;color:var(--ink);border-color:var(--line)}
.btn-outline:hover{border-color:var(--scarlet);color:var(--scarlet)}

/* ---------- header ----------
   Heritage Scarlet is the primary brand colour and leads every major surface.
   Royal Red is the accent: gradient ends, dividing rules, hover states.
   Gold on Scarlet is 3.75:1 — fine for large display text, so small text
   (this sub-line, nav links, kickers) is white and gold does the rules. */
/* Full-width gold rule, flush to the bottom of the header. 7px rather than the
   original 5px — the extra weight was the part of the experiments worth keeping.
   Tried at 12px since; too heavy, and 7px is settled.
   Even padding top and bottom: the tallest thing in here is the Tickets button,
   and a button is a box with no overhang, so equal padding reads as equal. */
/* --hdr-h is measured and published by site.js — the real height of this bar,
   gold rule included. Everything that has to clear the header reads it rather
   than carrying its own copy of the number. 73px is only the value used before
   the script has run and on a page with no script at all. */
:root{--hdr-h:73px}
.site{position:sticky;top:0;z-index:100;background:var(--scarlet);
  border-bottom:7px solid var(--gold)}

/* Going down the page on a phone the header leaves; coming back up it returns.
   The class is put on and taken off by site.js, which only ever does so on a
   touch layout, never above the first screenful, and never while the menu is
   open. transform rather than top, so it costs no layout and cannot shift the
   page as it moves. */
.site{transition:transform .28s ease}
.site.gone{transform:translateY(-100%)}
@media(prefers-reduced-motion:reduce){
  /* Asked for less movement, so it does not slide — it is simply there or not,
     which is still the behaviour, without the travel. */
  .site{transition:none}
}
.hdr{display:flex;align-items:center;gap:24px;padding:11px 24px}
.brand{display:flex;align-items:center;gap:12px;text-decoration:none;color:#fff;flex:0 0 auto}
/* LOGO VARIANTS — gus-logo.png is the FLAT mark, for small sizes. The shadowed
   mark (gus-logo-shadow.png) is for large reproductions; below roughly 120px the
   offset shadow closes up and reads as dirt rather than depth.
   Use .logo-lg on any logo rendered at 120px or more. */
.brand img{height:44px;width:auto}
.logo-lg{content:url('../img/gus-logo-shadow.png')}
/* Nothing carries .logo-lg at the moment — the footer logo went back to 54px.
   The rule stays because it is the brand rule, not a leftover: the day anything
   is rendered at 120px or more it needs this, and the rule is where the
   instruction above it can be found. */
/* The name is scaled by site.js to exactly match the sub-line's width — the two
   are measured in the browser, because estimating from font metrics gets it
   wrong by enough to notice. 20px is only the starting point; the script
   overwrites it. --lockup is the resolved size. */
.brand span{display:block}
.brand b{font-weight:900;font-size:var(--lockup,20px);letter-spacing:.06em;display:block;
  line-height:1;white-space:nowrap}
.brand i{font-style:normal;font-size:10px;letter-spacing:.15em;text-transform:uppercase;
  color:#fff;opacity:.92;display:block;margin-top:3px;white-space:nowrap}
/* The current-page underline runs down to meet the gold rule, so the two join
   into a T rather than the underline floating above it. For that the links have
   to reach the very bottom of the header: the nav stretches to the full content
   height, then eats the header's 11px bottom padding with a negative margin,
   which puts each link's bottom border flush against the gold. The link's own
   11px bottom padding puts the text back on the optical centre it had before.
   The Tickets button opts out of the stretch — it's a box, not a tab. */
.nav{display:flex;gap:20px;margin-left:auto;align-items:stretch;
  align-self:stretch;margin-bottom:-11px}
/* The highlight is 4px against the rule's 7px. Tried at 7px so the two strokes
   of the T matched; it read as heavy, and 4px is right. */
.nav a{font-weight:700;font-size:13px;letter-spacing:.05em;text-transform:uppercase;
  color:#fff;text-decoration:none;display:flex;align-items:center;
  padding:0 0 11px;border-bottom:4px solid transparent}
.nav a:hover,.nav a[aria-current=page]{border-color:var(--gold);color:#fff}
/* .nav a sets white for the links, and it out-specifies .btn-gold's own colour —
   so the Tickets button has to claim ink back explicitly, resting AND hover.
   Without this it renders white on gold, which is 1.7:1 and close to illegible. */
.nav .btn,.nav .btn:hover{color:var(--ink)}
.nav .btn{align-self:center;margin-left:6px;margin-bottom:11px;padding:11px 20px;
  font-size:12px;border-bottom:2px solid var(--gold)}

/* NO OPTICAL NUDGE HERE, and it is worth saying why not.
   The Tickets button and the icons were once pushed down 3px on the theory that
   the 7px gold rule reads as part of the same block, so centring on the scarlet
   alone leaves things 3.5px high. It was a nice argument and it was wrong: on
   screen the button then sat visibly low, worse than what it replaced.
   The measurement was right all along — the scarlet runs 71.1px and the
   button's centre is at 35.5px, which is exactly half. Leave it alone. */

/* ---- social links in the header ----
   Deliberately quieter than everything else up here. The nav takes people
   through the site and the Tickets button is the one thing we want pressed;
   three icons at 80% white are a way out to somewhere else, and should not
   compete with either. They come up to full white on hover.

   Marked out from the nav by a hairline rather than by extra space, because
   space alone at this size reads as a gap rather than a division. They opt out
   of the nav's full-height stretch — these are icons, not tabs, so they take no
   underline and centre on the row like the button does. */
.social{display:flex;align-items:center;gap:2px;align-self:center;
  margin-bottom:11px;margin-left:14px;padding-left:14px;
  border-left:1px solid rgba(255,255,255,.22)}
/* These are inside .nav, so `.nav a` matches them too — and that rule turns a
   link into a full-height tab: 11px of bottom padding and a 4px bottom border
   for the current-page underline. Both selectors are one class and one element,
   so they have equal specificity and .social a only wins on the properties it
   actually names. It named neither of those.

   The result: everything is border-box, so a 34px button with 11px of padding
   and a 4px border had 19px of content area left, and the icon centred in that
   — 7.5px above the middle of the button. The hover rule would also have drawn
   a gold underline beneath each icon. Both are undone explicitly here. */
.social a{display:grid;place-items:center;width:34px;height:34px;
  padding:0;border-bottom:0;
  color:rgba(255,255,255,.8);transition:color .15s}
.social a:hover{color:#fff;border-color:transparent}
.social svg{width:19px;height:19px;display:block}
/* 44 by 44. The three bars occupy only 24 by 16 of it; the rest is padding,
   which is invisible and is exactly the point — a target the size of a
   fingertip rather than the size of the drawing on it. */
.burger{display:none;background:none;border:0;cursor:pointer;flex-direction:column;
  justify-content:center;align-items:center;
  gap:5px;width:44px;height:44px;padding:0;margin-left:auto}
.burger span{display:block;width:24px;height:2px;background:#fff}

/* ---------- hero ---------- */
/* overflow:hidden is load-bearing, not tidiness. .hero-img is deliberately taller
   than this box so it can drift for the parallax; without clipping, that extra
   9% top and bottom simply paints outside the hero — and since .sec has no
   background of its own, the spill below showed as a strip of photograph between
   the gold "next performance" bar and What's On. .quote had this from the start;
   the hero didn't, because until the parallax nothing overflowed it. */
.hero{position:relative;color:#fff;isolation:isolate;background:var(--ink-2);
  overflow:hidden}
/* Overhangs top and bottom so it can drift against the scroll without ever
   showing an edge — the same trick as the quote photograph, gentler, because
   this one is on screen the moment the page opens. */
.hero-img{position:absolute;inset:-9% 0;z-index:-2;background-size:cover;
  background-position:center 40%;background-repeat:no-repeat}
/* Two layers, so the photograph still reads:
   1. a neutral scrim, strongest behind the text on the left, fading off to the
      right — this is what carries the legibility, not the colour;
   2. a light Heritage Scarlet wash, deepening to Royal Red at the base where it
      meets the gold bar. Kept well under a third so the image shows through. */
.hero::after{content:'';position:absolute;inset:0;z-index:-1;
  background:
    linear-gradient(90deg,
      rgba(20,16,15,.72) 0%,
      rgba(20,16,15,.58) 40%,
      rgba(20,16,15,.30) 75%,
      rgba(20,16,15,.14) 100%),
    linear-gradient(180deg,
      rgba(190,29,46,.20) 0%,
      rgba(190,29,46,.28) 55%,
      rgba(165,14,14,.48) 100%)}
/* safety net for the body line, which sits lower over unpredictable image areas */
.hero .lede{text-shadow:0 1px 12px rgba(20,16,15,.55)}
/* No max-width of its own, so it keeps .wrap's 1180px and starts on the same
   left edge as every other section — including the gold "next performance" bar
   immediately beneath it, which is also a .wrap. It used to be capped at 880px,
   which centred it and pushed the headline 150px to the right of everything
   else on the page. The reading measure is still controlled, just not here:
   .hero .lede caps itself at 600px, which is what that 880 was really for. */
.hero-in{padding:96px 24px 104px}
.hero h1{text-shadow:0 4px 34px rgba(0,0,0,.45)}
/* The whole headline is white — the gold bar underneath is the only gold here,
   which keeps the accent doing one job rather than two. */
.hero h1 em{font-style:normal;color:inherit}
.hero .lede{max-width:600px;margin:22px 0 34px;color:rgba(255,255,255,.93)}
.hero-cta{display:flex;gap:14px;flex-wrap:wrap}
/* White, not gold: this is 12px text on Heritage Scarlet, where gold is 3.75:1. */
/* column-gap MUST stay 0. The gold divider is a ::before inside the following
   span, so any column gap is added on its left only — the pipe then sits that
   much nearer the word on its right. With the gap at zero the spacing comes
   entirely from the divider's own symmetric 12px margins, and the .16em
   letter-space that trails both the previous word and the pipe itself falls on
   each side equally. Row gap still applies when the strip wraps on a phone. */
.proof{display:flex;column-gap:0;row-gap:8px;flex-wrap:wrap;align-items:center;
  margin:0 0 26px;font-weight:700;font-size:12px;letter-spacing:.16em;
  text-transform:uppercase;color:#fff}
.proof span{display:inline-flex;align-items:center}
.proof span+span::before{content:'|';margin:0 12px;color:var(--gold);opacity:1;font-weight:500}

/* The rotating honour. Every entry is stacked in one grid cell, so the strip is
   sized by the longest and nothing shifts as they change — a chip that resized
   itself would nudge the whole line every few seconds. Only the current one is
   visible; the rest stay in the document for screen readers, which get the
   complete list rather than whichever happened to be on screen. */
/* The stacking goes on an inner .cycle, NOT on the .proof-cycle span itself.
   `.proof span+span::before` draws the gold divider as a pseudo-element inside
   that span — make the span a grid and the divider becomes a grid item, lands
   in row two, and drags the text out of line. Leaving the span as an ordinary
   flex item keeps the divider beside the text where it belongs. */
.proof-cycle .cycle{display:inline-grid;align-items:center}
.cycle b{grid-area:1/1;font-weight:700;opacity:0;transition:opacity .45s ease;
  white-space:nowrap;text-align:left}
.cycle b.on{opacity:1}
/* The longest honour is about 280px once letter-spaced, which overflows the
   narrowest phones. Below that, let it wrap — the grid still stacks them, so
   the strip becomes two lines tall rather than running off the screen. */
@media(max-width:480px){.cycle b{white-space:normal}}

/* The rotating occasion above BOOK THE BAND. Same stacking device as the hero
   chip: every line in one grid cell, so the block is as tall as the tallest and
   the heading beneath it never moves as they change. Centred, because the CTA
   section is. */
.cta-cycle .cycle{display:inline-grid;align-items:center;text-align:center}
.cta-cycle .cycle b{text-align:center}
@media(max-width:560px){.cta-cycle .cycle b{white-space:normal}}
@media(prefers-reduced-motion:reduce){
  /* Shown one after another as ordinary text rather than fading. */
  .cta-cycle .cycle{display:inline}
  .cta-cycle .cycle b{opacity:1}
  .cta-cycle .cycle b+b{display:none}
}
/* Nothing should move by itself for anyone who has asked it not to. All of them
   are then shown in sequence, which the strip can carry. */
@media(prefers-reduced-motion:reduce){
  .proof-cycle .cycle{display:inline}
  .cycle b{opacity:1;transition:none}
  .cycle b+b::before{content:'|';margin:0 10px;color:var(--gold);font-weight:500}
}

/* Heritage Scarlet across the body, Royal Red only in the far corner. */
/* Ink, the same treatment as the enquiry panel on Book Us: flat black ground,
   white heading, gold kicker, and the black crest reading as a shade rather
   than a shape. Deliberately not scarlet — the header above is already scarlet,
   so a scarlet banner directly beneath it stacked two reds with only the gold
   rule between them. */
.page-head{background:var(--ink);
  color:#fff;padding:64px 0 58px;border-bottom:5px solid var(--gold)}
.page-head h1{font-size:clamp(34px,5.5vw,60px)}
/* THE THREE LINES ARE ONE LOCKUP. The gold bar sits under the heading at
   exactly its own thickness — 8px under an 8px bar, which is the rule the whole
   site is set to — while the kicker floated nineteen pixels above it, so the
   pair read as two separate things that happened to be stacked. The air above
   the capitals is now the air below them.

   Nineteen became eight by taking eleven off the box, not off the eye: seven of
   those pixels are the leading under the kicker's own line — the space its
   descenders would use if it had any, and it is capitals, so it never does. The
   correction is in the kicker's em rather than in pixels, so it still holds if
   the kicker is ever set at another size. */
.page-head .kicker{color:var(--gold);margin-bottom:calc(8px - .58em)}
.page-head .kicker + h1{margin-top:0}
.page-head .lede{max-width:660px;margin-top:18px;color:rgba(255,255,255,.94)}

/* THE FRONT PAGE'S OWN TITLE, in the white under the banner. The banner is
   addressed to the person — good evening, DANIEL — so the page itself would
   otherwise go unnamed, and a front page with no title reads as the middle of
   something. The same heading device as every other screen in here, sitting on
   the same left edge as the strip and the tiles below it. */
.ad-intro-home{margin:0 0 26px}
/* AND AT FULL SIZE, because it is the page's heading and not a caption on the
   way to one. Deliberately the same clamp as the banner's own h1, so the two
   titles on this screen track each other at every width — the ink says who is
   here, the white says what this is, in the same voice. */
.ad-intro-home h2{font-size:clamp(34px,5.5vw,60px)}
/* And the bar under it is the banner's, not the section pages': the thickness
   goes with the size of the word it is under, and this word is now the same
   size as the one in the ink above it. */
.ad-intro-home h2.rule::after{--bar:8px}

/* ---------- next performance bar ---------- */
.nextbar{background:var(--gold);color:var(--ink)}
.nextbar-in{display:flex;align-items:center;gap:18px;padding:14px 24px;flex-wrap:wrap}
/* The black tag looked to be sitting high in its own box, and it was.
   The label inherited the body's 1.65 line-height, so an 11px capital sat in an
   18px line box. Capitals have no descenders, so all the ink is in the top part
   of that box and the empty descender space below it pushes the visible block
   above centre — the padding was even, but the thing inside it wasn't.

   line-height:1 takes the leading out, then 1px more above than below corrects
   for capitals sitting slightly high in the em itself. The letter-spacing also
   adds a trailing gap after the final letter, which shifts the label left of
   centre; padding-right carries 1px less to take that back out. */
.nb-tag{font-weight:900;font-size:11px;letter-spacing:.16em;text-transform:uppercase;
  background:var(--ink);color:var(--gold);border-radius:0;
  line-height:1;padding:9px calc(12px - .16em) 8px 12px}
.nb-body{font-weight:700;font-size:15px;flex:1 1 auto}
.nb-link{font-weight:700;font-size:13px;letter-spacing:.06em;text-transform:uppercase;
  text-decoration:none;border-bottom:2px solid var(--ink);white-space:nowrap}

/* ---------- sections ---------- */
.sec{padding:84px 0}
.sec-tint{background:var(--tint)}
.dark{background:var(--ink);color:#fff}
.dark h2,.dark h3{color:#fff}
.dark p{color:rgba(255,255,255,.82)}

/* Heritage Scarlet section. White text only — gold small text fails here. */
.red{background:var(--scarlet);color:#fff}
.red h2,.red h3{color:#fff}
.red p{color:rgba(255,255,255,.94)}
.red .kicker{color:#fff}
.red .txtlink{color:#fff;border-bottom-color:rgba(255,255,255,.5)}
.red .txtlink:hover{border-bottom-color:var(--gold)}
.red .venues span{border-color:rgba(255,255,255,.45);background:rgba(0,0,0,.16)}
.red .btn-outline{color:#fff;border-color:rgba(255,255,255,.6)}
.red .btn-outline:hover{background:#fff;color:var(--scarlet);border-color:#fff}
.sec-head{display:flex;align-items:flex-end;justify-content:space-between;gap:24px;
  margin-bottom:36px;flex-wrap:wrap}
/* :not(.kicker), and that is the whole point of it. `.sec-head p` is a class
   plus an element, so it outranks the bare `.kicker` class and was painting the
   little heading above the title mute grey — but only inside a .sec-head. Seven
   of them across three pages were grey while every other kicker on the site was
   scarlet, which is why they looked arbitrary: the rule that greyed them was
   meant for the sentence underneath, and caught the kicker on the way past. */
.sec-head p:not(.kicker){margin:10px 0 0;color:var(--mute);max-width:56ch}
.dark .sec-head p{color:rgba(255,255,255,.75)}

/* The .prod / .prods rules that used to live here styled the three numbered
   production cards on Book Us. That menu is gone — the band doesn't sell a fixed
   set of productions — and nothing else on the site used them, so they have gone
   with it rather than sitting here waiting to be wondered about. See .offers. */

/* ---------- record / proof strip ---------- */
/* Heritage Scarlet panels divided by Royal Red rules — the accent doing its job.
   Gold numerals are 42px display text, so 3.75:1 clears the AA-large threshold. */
.record{display:grid;grid-template-columns:repeat(4,1fr);gap:2px;background:var(--royal)}
.rec{background:var(--scarlet);padding:32px 24px}
.rec b{display:block;font-weight:900;font-size:42px;color:var(--gold);line-height:1}
.rec i{font-style:normal;display:block;font-size:13.5px;color:rgba(255,255,255,.94);
  margin-top:8px;line-height:1.4}

/* The two cycling panels. Every honour is stacked in the same grid cell, so the
   panel is as tall as the longest one and the row never changes height as they
   turn over — a panel that resized itself would shunt the whole strip. */
.rec-cycle{display:grid;align-items:start}
/* One out, then the next in — not a crossfade. Overlapping them leaves two
   honours half-visible over the same pixels, which reads as a smudge rather than
   a change. The gap between the two is timed in site.js, which reads this
   duration back off the element so the two can't fall out of step.
   Same treatment as the rotating chip in the hero. */
.rec-cycle .stat{grid-area:1/1;opacity:0;transition:opacity .85s ease}
.rec-cycle .stat.on{opacity:1}
@media(prefers-reduced-motion:reduce){
  /* No movement: each panel shows its opening honour and stays there. */
  .rec-cycle .stat{transition:none}
}

/* ---------- events ---------- */
.tag{display:inline-block;font-weight:700;font-size:10.5px;letter-spacing:.13em;
  text-transform:uppercase;padding:4px calc(10px - .13em) 4px 10px;margin-bottom:8px}
.tag-contest{background:#FFF6D9;color:#8A6A00}
.tag-concert{background:#FDEBED;color:var(--royal)}
.ev-note{font-size:13px;color:var(--mute);font-style:italic;text-align:center;padding:8px}

/* ---------- cards ---------- */
.cards{display:grid;grid-template-columns:repeat(3,1fr);gap:26px}
.card{background:#fff;border:1px solid var(--line);text-decoration:none;color:inherit;
  display:flex;flex-direction:column;transition:.18s}
.card:hover{transform:translateY(-3px);box-shadow:0 14px 34px rgba(20,16,15,.1)}
.card-img{aspect-ratio:16/10;background:var(--tint) center/cover no-repeat}
.card-body{padding:22px 24px 26px}

/* A small scarlet line on a card. News puts it under the title as the date;
   Listen puts it above as a label ("Over 100,000 views", "Whit Friday") — which
   is why the name is only half right, and why the spacing is set per position
   rather than baked into the class. */
.card-date{font-weight:700;font-size:11.5px;letter-spacing:.13em;text-transform:uppercase;
  color:var(--scarlet)}
.card h3{font-size:20px;margin-bottom:9px}

/* Above a title (Listen): space below it, separating it from the heading.
   Under a title (News): the heading's own 9px is already there, so it only
   needs space beneath, before the blurb. Tighter above than a paragraph would
   be, so it reads as belonging to the title rather than starting the text. */
.card-date + h3{margin-top:0}
.card h3 + .card-date{margin:-3px 0 9px}
.card-body > .card-date:first-child{margin-bottom:8px}
.card p{font-size:14.5px;color:var(--mute);margin:0}

/* ---------- split ---------- */
.split{display:grid;grid-template-columns:1.15fr 1fr;gap:60px;align-items:center}
.split-2{display:grid;grid-template-columns:1fr 1fr;gap:56px}

/* ---------- book us: what we do ----------
   Deliberately not cards. Cards look like products with prices behind them, and
   the whole point of this section is that these are examples of what the band
   has done rather than a catalogue to choose from.

   THE SUB-HEADINGS ARE THE BAND'S OWN DEVICE, lifted from the social media plan,
   where a Royal Red strip of white Bold text heads forty-one blocks. The plan's
   brand note is explicit about the colour: Royal Red #A50E0E for on-page
   elements — badges, boxes and rules — "since none sit on a coloured
   background", which is exactly the case here. Heritage Scarlet leads whole
   surfaces; Royal Red does the small furniture on white. 7.87:1.

   TWO THINGS TAKEN FROM THE DOCUMENT ITSELF RATHER THAN FROM ITS BRAND NOTE.

   The strip is as wide as its words, not as wide as the column. Every strip in
   the plan is its own single-cell table sized to its contents: measured across
   them, the width holds at 110–134 twentieths of a point per character from a
   thirteen-character heading to a forty-seven-character one, and the widest
   never reaches two thirds of the page. Hence inline-block.

   And the text is sentence case. The brand note says Title Case for
   sub-headings; the document says otherwise forty times out of forty-one —
   "Our headline targets", not "Our Headline Targets". Not one is in caps.
   Where the note and the practice disagree, the practice is what the band
   actually looks like.

   THE INSET IS TIGHT, AND TIGHTER STILL AT THE SIDES. Measured from the cell
   margins: 36 twentieths of a point top and bottom against 6 at the sides — the
   fill is drawn almost exactly round the words, and it is closer at the left and
   right than above and below, which is the reverse of how a button is padded.
   The leading is tight with it, at 0.96 of single spacing.

   Translated rather than copied. Literally 6 twentieths of a point is 0.4px at
   this size, which would have the letters touching the red; 5px keeps a hair of
   air without loosening the shape. Everything else follows the original: 4px
   above and below, and the leading pulled in to 1.2 so the strip sits on the
   text rather than around it. */
/* Two columns, not three. Six small items across a white field read as a list of
   minor points; the same six at half the count per row read as six things the
   band does. Nothing has been added to make this stronger — no boxes, no ground,
   no rules. It is bigger, there is more air between, and the body text is ink
   rather than grey. Confidence rather than decoration.

   The measure is capped: a two-column layout at this width would otherwise run
   to ninety characters a line, which is where prose stops being read. */
.offers{display:grid;grid-template-columns:repeat(2,1fr);gap:40px 56px;margin-top:42px}
.offer h3{display:inline-block;background:var(--royal);color:#fff;font-weight:700;
  font-size:20px;line-height:1.2;letter-spacing:.01em;text-transform:none;
  padding:5px 7px;margin:0 0 15px}
.offer p{margin:0;font-size:16.5px;line-height:1.62;color:var(--ink);max-width:50ch}
@media(max-width:760px){
  .offers{grid-template-columns:1fr;gap:30px}
  .offer h3{font-size:18px}
}

/* ---------- book us: the collage ----------
   EVERY PICTURE IS THE SAME HEIGHT; THE WIDTHS DO WHATEVER THE PICTURE WANTS.
   That is the whole idea. A grid of fixed cells forces every photograph into the
   same shape and gives ragged rows when the shapes differ; here the height is
   the constant, each picture is as wide as its own proportions make it, and the
   row stretches to fill the line. Uneven widths, dead-level rows.

   HOW IT WORKS. Each figure declares --ar, its width divided by its height.
   flex-basis starts it at --ar × the row height, which is its true width, and
   flex-grow shares out whatever is left over in the same proportion, so wider
   pictures take more of the slack. Nothing has to be measured in JavaScript and
   nothing needs to know how many photographs there are.

   ADDING ONE: copy a <figure>, set --ar from the file's own dimensions —
   300x169 is 1.78, 2048x1363 is 1.50 — and drop it anywhere in the list. The
   rows re-justify on their own. If --ar is left off it falls back to 3:2, which
   is right for most photographs and wrong only in a way nobody notices.

   The caption sits on the picture rather than under it. Underneath, a one-line
   caption and a two-line caption make the row ragged again at the bottom, and
   the whole block was taking too much of the page. */
.photo-set{display:flex;flex-wrap:wrap;gap:8px;--h:210px}
.photo-set figure{margin:0;position:relative;overflow:hidden;
  flex:var(--ar,1.5) 1 calc(var(--ar,1.5) * var(--h))}
.photo-set .photo{height:var(--h);background-size:cover;background-position:center 40%;
  background-repeat:no-repeat;background-color:var(--ink-2)}
/* The last row would otherwise stretch a lone picture across the full width. */
.photo-set::after{content:'';flex-grow:1e6}
.photo-set figcaption{position:absolute;left:0;right:0;bottom:0;
  padding:26px 13px 10px;color:#fff;font-size:12.5px;line-height:1.35;
  background:linear-gradient(180deg,rgba(20,16,15,0) 0%,rgba(20,16,15,.55) 45%,
                                    rgba(20,16,15,.88) 100%)}
@media(max-width:900px){.photo-set{--h:170px}}
@media(max-width:560px){
  /* One at a time, at their own shapes — justifying two per row at this width
     leaves slivers. */
  .photo-set{--h:auto;display:block}
  .photo-set figure{margin-bottom:8px}
  .photo-set .photo{height:auto;aspect-ratio:var(--ar,1.5)}
}

/* ---------- book us: what it involves ---------- */

/* This section was briefly a two-column head — heading one side, prose the
   other. It measured badly. The heading column stacked to about 145px and the
   prose beside it to about 239px, so whichever way they were aligned one of
   them was left hanging: top-aligned put a 94px hole in the bottom left, right
   where the panel starts, and bottom-aligned dropped the heading to nothing.
   Two columns only balance when the two things in them are a similar size, and
   a heading is never the size of three paragraphs.

   So the head is one full-width block, and the two remarks that used to pad the
   right column have gone below the panel as a matched pair, where they are the
   same size as each other and do balance. */
.spec-lede{max-width:62ch;margin:18px 0 0}

/* The six answers a promoter actually rings up to ask.
   These were previously laid two-across inside the narrow half of a .split:
   190px of label against what worked out at a 20px value column, so every
   answer wrapped to roughly one word per line. They now take the full wrap and
   read three across, which is the measure the copy was written for.

   The rules between them are drawn by a 1px grid gap over a --line ground
   rather than by a border on each cell. One continuous table, no doubled
   hairlines where cells meet, and nothing to special-case at the edges. */
.specs{display:grid;grid-template-columns:repeat(3,1fr);gap:1px;
  background:var(--line);border:1px solid var(--line);margin-top:40px}
.spec{background:var(--paper);padding:26px 28px 30px}

/* Royal red, not mute grey. These are the labels on a specification sheet and
   they are meant to be found at a glance — 7.87:1 on paper, and it ties the
   panel to the red strips further up the page. */
.spec dt{font-weight:700;font-size:12px;letter-spacing:.12em;text-transform:uppercase;
  color:var(--royal);margin:0 0 13px}
/* No max-width here: the cell is 321px at full size, which is about a
   40-character measure on its own. A ch cap on top of that would only leave a
   ragged strip of empty card down the right of every answer. */
.spec dd{margin:0;font-size:16px;line-height:1.58;color:var(--ink)}

/* The same device used again in the Sponsor section, where it sits in the
   narrow half of a .split and carries four short figures rather than six
   sentences. Two across, not three. It had the identical squashed-value
   problem before this change and simply wasn't as obvious, because "4,900
   followers" survives a narrow column better than a full sentence does. */
.specs-narrow{grid-template-columns:repeat(2,1fr)}

/* The two remarks under the panel. Equal columns, equal size, equal colour —
   the balance is doing the work here, so neither may be emphasised over the
   other.

   They are 225 and 204 characters, which at this measure comes to four lines
   and three. Matching the lengths to make them bottom out level would mean
   padding a sentence to fit a column, which is the wrong way round. Instead
   each gets a short rule across the top, so the pair is anchored at the head
   where they are exactly level and the ragged foot stops signifying. Two
   separate rules with the column gap between them, not one continuous line —
   that would read as a second border under the panel. */
.spec-notes{display:grid;grid-template-columns:1fr 1fr;gap:22px 56px;margin-top:34px}
.spec-notes p{margin:0;padding-top:18px;border-top:2px solid var(--line);
  font-size:15.5px;line-height:1.66;color:var(--mute)}
.spec-notes b{color:var(--ink);font-weight:700}

/* Still used on its own by the Sponsor panel, which has one remark, not two. */
.spec-note{margin:24px 0 0;font-size:14.5px;line-height:1.6;color:var(--mute);max-width:74ch}

/* Two across once the third column would drop below about 300px, one across on
   a phone — a definition list is the one layout that loses nothing by stacking. */
@media(max-width:980px){
  .specs{grid-template-columns:repeat(2,1fr)}
}
@media(max-width:620px){
  .specs,.specs-narrow{grid-template-columns:1fr}
  .spec{padding:22px 22px 24px}
  /* Side by side is the whole point of the pair; once they'd be 40 characters
     wide it isn't, so they stack. */
  .spec-notes{grid-template-columns:1fr}
}

.venues{display:flex;flex-wrap:wrap;gap:10px;margin-top:8px}
.venues span{border:1px solid var(--line);padding:8px 16px;font-size:14px;background:#fff}
.dark .venues span{border-color:rgba(255,255,255,.25);background:rgba(255,255,255,.05)}

/* ---------- steps ---------- */
.steps{display:grid;grid-template-columns:repeat(3,1fr);gap:28px;counter-reset:s}
.step{counter-increment:s;position:relative;padding-top:56px}
.step::before{content:counter(s,decimal-leading-zero);position:absolute;top:0;left:0;
  font-weight:900;font-size:34px;color:var(--gold)}
.step h3{font-size:18px;text-transform:uppercase;letter-spacing:.03em;margin-bottom:8px}
.step p{font-size:15px;color:var(--mute);margin:0}
.dark .step p{color:rgba(255,255,255,.78)}

/* ---------- roster ---------- */
/* One click to any section. Twenty-nine players is a long scroll however it's
   laid out; this is what stops it being a slog, without hiding anybody. */
.roster-jump{display:flex;flex-wrap:wrap;gap:8px;margin:0 0 38px;
  padding-bottom:26px;border-bottom:1px solid var(--line)}
.roster-jump a{font-weight:700;font-size:12px;letter-spacing:.1em;text-transform:uppercase;
  text-decoration:none;color:var(--ink);background:var(--tint);
  border:1px solid var(--line);padding:9px calc(15px - .1em) 9px 15px;transition:.18s}
.roster-jump a:hover{background:var(--ink);border-color:var(--ink);color:#fff}

/* scroll-margin keeps a jumped-to heading clear of the sticky header. */
/* scroll-margin keeps a jumped-to heading clear of the sticky header — the real
   height of it plus a little air, rather than a number typed in and left to
   drift when the header changes. */
.section-block{margin-bottom:44px;scroll-margin-top:calc(var(--hdr-h) + 22px)}
.section-block h3{margin-bottom:22px}

/* The heading IS the control, so it takes the whole width — a section is folded
   by clicking its name, not by hunting for a small arrow at one end. The scarlet
   rule that was on the h3 moves onto the button, which is the thing being
   pressed. */
.sec-toggle{width:100%;display:flex;align-items:center;gap:12px;
  background:none;border:0;border-bottom:2px solid var(--scarlet);
  padding:0 0 10px;margin:0;cursor:pointer;text-align:left;color:inherit;
  font:inherit;font-size:15px;font-weight:900;text-transform:uppercase;
  letter-spacing:.16em}
.sec-toggle:hover{border-bottom-color:var(--gold)}
.sec-name{flex:1 1 auto}

/* How many players are in there. Reads as information when the section is open
   and as a reason to open it when it isn't. */
.sec-count{font-size:12px;font-weight:700;letter-spacing:.08em;color:var(--mute)}

/* The open/shut mark. A triangle rotated rather than two different characters,
   so it turns rather than jumps — and the transition is on transform only, which
   the compositor handles without touching layout.
   Marked aria-hidden by being CSS content: generated content is not in the
   accessibility tree, and aria-expanded on the button already says the same
   thing properly. */
.sec-toggle::after{content:'';width:0;height:0;flex:0 0 auto;
  border-left:6px solid transparent;border-right:6px solid transparent;
  border-top:7px solid var(--scarlet);transition:transform .2s ease}
.sec-toggle[aria-expanded=false]::after{transform:rotate(-90deg)}
.sec-toggle[aria-expanded=false]{border-bottom-color:var(--line)}
/* Five across rather than four, and a squarer crop. Same photographs, roughly a
   third less page to get through. */
.players{display:grid;grid-template-columns:repeat(5,1fr);gap:18px}

/* .player is a <button> for anyone with a biography and a <div> for anyone
   without, so everything a button brings with it has to be unset: buttons come
   with their own font, a border, a background, centred text and a fixed width
   that ignores the grid. */
.player{text-align:left;font:inherit;color:inherit;background:none;border:0;
  padding:0;margin:0;width:100%;display:block}
.player-img{display:block;aspect-ratio:4/5;background:var(--tint) center/cover no-repeat;
  margin-bottom:10px;position:relative;overflow:hidden}
.player-img.blank{background:repeating-linear-gradient(45deg,#F3EEEA,#F3EEEA 10px,#FAF6F3 10px,#FAF6F3 20px)}
.player b{display:block;font-weight:700;font-size:16px}
.player .seat{display:block;font-size:13.5px;color:var(--mute)}

/* ---- a player you can open ----
   The cue sits inside the photograph, along its bottom edge, and slides up on
   hover and focus. It stays in the accessibility tree whether or not it is
   showing, so the button never announces itself as nothing but a name — and it
   only exists on the cards that actually lead somewhere. */
.player-open{cursor:pointer}
.player-cue{position:absolute;left:0;right:0;bottom:0;
  background:var(--scarlet);color:#fff;                 /* 6.17:1 */
  font-size:11px;font-weight:700;letter-spacing:.12em;text-indent:.12em;
  text-transform:uppercase;
  padding:4px 8px;text-align:center;line-height:1.35;
  transform:translateY(100%);transition:transform .22s ease}
.player-open:hover .player-cue,
.player-open:focus-visible .player-cue{transform:translateY(0)}

/* The name underlines in gold under the cursor, which together with the cue
   sliding up is enough to say the card does something.
   The photograph deliberately does NOT scale on hover, tempting as it is: these
   are tight portrait crops, and growing one inside a fixed frame trims a few
   per cent off the top and bottom — which on a head-shot means shaving the top
   of somebody's head. Not worth it for a flourish. */
.player-open:hover b{text-decoration:underline;text-underline-offset:3px;
  text-decoration-thickness:3px;text-decoration-color:var(--gold)}

@media(prefers-reduced-motion:reduce){
  .player-cue,.sec-toggle::after{transition:none}
}

.player.tbc .player-img{border:2px dashed var(--line)}
.player.tbc b{color:var(--mute);font-style:italic}
/* Dormant on purpose, paired with the commented-out "Play with us" section in
   book-us.html. The roster filters vacant seats out, so nothing carries these
   today; both come back together the day a seat is advertised. */
.player.vacancy .player-img{border:2px dashed var(--scarlet);background:#FFF8F8}
.player.vacancy b{color:var(--scarlet)}

/* ---------- the biography panel ----------
   This used to be a <details> opening inside its own cell of a five-column grid.
   That cell is about 212px, so a 1,750-character biography set at roughly
   twenty-six characters a line and ran to sixty-seven of them, in a column the
   width of a thumb, shoving the rest of the row down the page as it went.

   A native <dialog>, so the browser handles the focus trap, Escape, the inert
   background and returning focus to the card afterwards. What is styled here is
   only how it looks. */
/* The panel itself never scrolls — overflow:hidden, not auto. Only the column
   of words inside it does, so the photograph stays put however long somebody's
   career has been. A flex column with the inner row set to min-height:0 is what
   lets that row be shorter than its contents and hand the overflow down;
   without it the row grows to fit and the panel scrolls as one piece again. */
/* SIZED IN dvh, NOT vh — this matters on a phone and nowhere else.
   vh is the height of the screen with the address bar HIDDEN. While the bar is
   showing, which is most of the time, that is taller than what can actually be
   seen — so a panel sized to 100vh minus a margin still runs off the bottom by
   the height of the bar, and the close button goes with it. dvh is the space
   there is at this moment. The vh line stays first as the fallback for anything
   too old to know dvh, where the old behaviour is no worse than it was. */
.bio-dlg{width:min(1020px,calc(100vw - 48px));max-height:min(760px,calc(100vh - 64px));
  padding:0;border:0;background:var(--paper);color:var(--ink);
  overflow:hidden;position:relative;display:flex;flex-direction:column}
.bio-dlg{max-height:min(760px,calc(100dvh - 64px))}
/* THE PAGE BEHIND IS DARKENED AND BLURRED, and the two numbers are set
   together on purpose.

   The darkening was .72 on its own. A blur behind ink that opaque does almost
   nothing you can see — there is not enough of the page left showing for
   anything to be soft. So the ink comes down to .58 and the blur does the rest
   of the work: still plainly dark, but the roster behind now reads as an
   out-of-focus background rather than a dim one. Together they separate the
   panel from the page more completely than .72 flat did.

   8px, which is soft rather than frosted. Enough that no face behind is
   recognisable and no name readable, not so much that the page looks broken.

   Nothing here affects the words in the panel — the dialog has its own paper
   background — so there is no contrast question to answer. */
.bio-dlg::backdrop{background:rgba(12,9,8,.58);
  -webkit-backdrop-filter:blur(8px);
  backdrop-filter:blur(8px)}

/* Anything that cannot blur keeps the old, heavier darkening, so it separates
   the panel by the one means it has. Both spellings are asked about: Safari
   supported only the -webkit- one for years, and testing the plain name alone
   would send those versions here and give them the blur AND the heavier ink. */
@supports not ((backdrop-filter:blur(1px)) or (-webkit-backdrop-filter:blur(1px))) {
  .bio-dlg::backdrop{background:rgba(12,9,8,.72)}
}

/* ---- how it arrives ----
   The panel used to appear whole, in one frame, which reads as a jolt rather
   than as something opening — and made the click feel like a page change.
   It rises a little and fades, and the page behind goes out of focus with it,
   so the two halves of the effect belong to the same movement.

   ON [open] RATHER THAN A CLASS. The attribute appears the moment showModal()
   runs, so the animation starts with no second frame to wait for and no
   JavaScript to keep in step with the stylesheet.

   Nothing on the way out. Closing a dialog with an animation needs the browser
   to keep it painted after it stops being open, and getting that wrong leaves a
   panel that cannot be shut — a much worse fault than a brisk exit.

   .28s: long enough to read as a movement, short enough that somebody working
   down a roster opening one player after another is never waiting for it.

   Switched off for reduced motion rather than on for no-preference — the way
   the other thirteen movement rules in this file are written, and the way that
   fails safe: it runs unless somebody has asked it not to. */
.bio-dlg[open]{animation:bio-rise .28s cubic-bezier(.2,.75,.3,1) both}
.bio-dlg[open]::backdrop{animation:bio-veil .28s ease both}

@media(prefers-reduced-motion:reduce){
  .bio-dlg[open],.bio-dlg[open]::backdrop{animation:none}
}
@keyframes bio-rise{
  from{opacity:0;transform:translateY(16px) scale(.985)}
}
@keyframes bio-veil{
  from{opacity:0;-webkit-backdrop-filter:blur(0);backdrop-filter:blur(0)}
}

/* A closed dialog is hidden by the browser's own stylesheet, which says
   dialog:not([open]){display:none}. Author rules beat browser rules whatever
   their specificity, so the display:flex above quietly switched that off: the
   panel sat at the foot of the roster page, permanently visible, and the
   autofocus inside it sent the page straight to the bottom on load.

   Any rule that sets display on a <dialog> has to put this back. It is not
   optional and it is not belt and braces. */
.bio-dlg:not([open]){display:none}

.bio-in{flex:1 1 auto;min-height:0;
  display:grid;grid-template-columns:360px 1fr;gap:0;align-items:stretch}

/* The photograph fills its half however tall the biography turns out to be —
   these are portrait crops of wildly different sizes, so cover is the only thing
   that behaves. */
/* ---- the left column: who this is ----
   The photograph used to fill a 1:2 slot on its own, which left the choice
   between cropping a square portrait to a strip of its middle and leaving a
   dead white block underneath. The column carries the identity instead — the
   whole picture, then the seat, the name and the facts — on ink. The words fill
   what the picture does not. The crest watermark is not here: it stays in the
   white column behind the biography, where it has always been.

   Ink AROUND the photograph rather than white: a picture mounted on a dark
   ground reads as framed, where the same gap in white reads as something
   missing. That is the whole difference between the two versions of this. */
.bio-side{background:var(--ink);color:#fff;
  display:flex;flex-direction:column;min-height:100%}

/* FLUSH TO THE TOP AND BOTH SIDES. It had a margin around it, which made the
   picture look like something laid ON the column rather than the top of it.

   9:10, and that shape was measured rather than picked. The roster is square
   and 3:4 in roughly equal numbers, so any one slot costs something; across the
   nineteen photographs whose size is known:

     1:1    worst 25%   average 9.1%
     9:10   worst 17%   average 8.8%     <- this
     6:7    worst 21%   average 11.0%
     4:5    worst 26%   average 15.0%
     3:4    worst 31%   average 18.8%

   9:10 is the best of them on the worst case by eight points and the best on
   average as well, which is unusual enough to be worth writing down.

   Anchored to the top, so what a tall picture loses is the bottom of somebody's
   instrument rather than the top of their head. Centred across, because the one
   thing every one of these photographs has in the middle is a face. */
.bio-side .bio-photo{flex:0 0 auto;margin:0;height:auto;min-height:0;
  aspect-ratio:9/10;background-color:var(--ink);
  background-position:center top;background-size:cover}

.bio-id{flex:1 1 auto;min-height:0;padding:20px 30px 30px}
.bio-id .kicker{color:var(--gold)}
.bio-id h2{color:#fff;font-size:clamp(26px,3.4vw,38px)}

/* Label and answer on one line, ruled off from each other. Small caps for the
   label so the answer is what the eye lands on. */
.bio-facts{margin:26px 0 0;display:grid;gap:0}
.bio-facts>div{display:flex;justify-content:space-between;align-items:baseline;
  gap:16px;padding:10px 0;border-top:1px solid rgba(255,255,255,.16)}
.bio-facts dt{font-size:11px;font-weight:900;letter-spacing:.14em;
  text-transform:uppercase;color:rgba(255,255,255,.6)}
.bio-facts dd{margin:0;font-weight:700;font-size:15px;color:#fff;text-align:right}

/* THE WHOLE PHOTOGRAPH, NOT A CROP OF IT.

   This was center/cover. The column is 360 wide by up to 760 tall — about 1:2.1
   — and the photographs are square or near it. Filling a slot that shape from a
   square source throws away 52% of the width: measured across the roster, every
   picture was blown up between 2.5 and 2.7 times and showed about 140px of its
   300. Faces arrived cropped to the middle and enlarged, and the euphonium the
   player is holding was mostly outside the panel.

   The slot is nearly square now instead, which is the shape the photographs
   actually are — see the measured comparison above .bio-side .bio-photo. The
   worst any picture loses is 17% and the average is under 9%, against 52% for
   every single one of them before.

   NOT SOLVED BY BIGGER ORIGINALS. A 2000px source cropped to 1:2.1 loses the
   same 52% — it would be sharper and just as cut off. Resolution and framing
   are different faults, and this is the framing one. */
.bio-photo{background:var(--tint) center top/contain no-repeat;min-height:100%}
/* Hiding it needs no rule of its own: [hidden]{display:none !important} at the
   top of this file already outranks anything set here, which is the whole reason
   that rule carries an !important. The folding grids rely on it too. */

/* The left column stays whether or not there is a photograph. It used to
   collapse to one column when there was none, because the column WAS the
   photograph and an empty one was just a grey rectangle. It now carries the
   seat, the name and the facts as well, so with no picture it is a name plate
   rather than a gap — and a panel that changed shape depending on whether
   somebody had sent a photograph in was drawing attention to exactly the thing
   it should not. */

/* .bio-text holds the crest and does not move; .bio-scroll inside it carries the
   words and the padding. Splitting them is what keeps the watermark pinned to
   the bottom-left corner of the panel — an absolutely positioned crest inside a
   scrolling box would slide up the page along with the text.
   .mark supplies position:relative, overflow:hidden, and lifts .bio-scroll above
   the watermark, so none of that is repeated here. */
.bio-text{min-height:0;display:flex;flex-direction:column;position:relative}

/* The crest, bottom left, exactly as on every section elsewhere: no size
   override here at all, so it takes the standard 'auto 100%' and fills the full
   height of the panel — top edge flush with the top, bottom flush with the
   bottom, width falling out of that. At this panel's proportions that comes to
   about 599px across a 660px column, so it very nearly reaches the right edge
   too. It was briefly held back to 58%, which left it sitting in the corner
   looking like a small graphic rather than the watermark it is.

   The brand note says once per page and this is technically a third; it is on a
   surface that covers the page rather than sitting in it, so it is never seen at
   the same time as the other two. */

.bio-scroll{flex:1 1 auto;min-height:0;overflow-y:auto;padding:44px 48px 46px}

/* Focus lands here when the panel opens, so the biography is what gets
   announced rather than the close button. Programmatic focus on a tabindex=-1
   container doesn't match :focus-visible, so no ring is drawn — but belt and
   braces, because a ring round the whole text column would look like a fault. */
.bio-scroll:focus{outline:none}

/* ---- the panel's own scrollbar ----
   Recolouring the system scrollbar was the first attempt and it still looked
   like a system scrollbar, because that is exactly what it was. So the native
   one is taken out and we draw our own, the same device already sitting under
   the homepage reel — turned on its side, and inset from the edges top and
   bottom so it reads as part of the panel rather than as the browser's furniture
   bolted to the side of it.

   The bar is a sibling of the scrolling box, not inside it, so it stays put
   while the words move. .mark>* would otherwise force position:relative onto it
   — hence the two-class selector, which outranks that. */
.bio-scroll{scrollbar-width:none;-ms-overflow-style:none}
.bio-scroll::-webkit-scrollbar{display:none}

/* Top starts at 62px, not 44px. The close button is 44px square in that same
   corner, so a bar starting at 44 began exactly where the button ended and the
   two ran together into a single vertical shape. 18px of clear air separates
   them, which is the same gap the bar keeps from the foot of the panel. */
.bio-text .bio-bar{position:absolute;top:62px;bottom:46px;right:18px;width:4px;
  background:var(--line);z-index:2;cursor:pointer}

/* The thumb is wider than the track it runs in, so it reads as the moving part
   rather than as a filled portion of a tube — and it gives the pointer a little
   more to catch hold of. */
.bio-text .bio-thumb{position:absolute;left:-2px;right:-2px;top:0;
  background:var(--gold);will-change:transform;transition:background .15s}
.bio-bar:hover .bio-thumb,.bio-bar.dragging .bio-thumb{background:#ffdf5e}

.bio-text .kicker{margin-bottom:10px}
.bio-body{margin-top:22px}
.bio-body p{margin:0 0 1em;font-size:16.5px;line-height:1.68}
.bio-body p:last-child{margin-bottom:0}

/* Square, scarlet, and pinned to the corner of the panel rather than floating
   over the photograph, where it would land on somebody's face. 44px so it clears
   the 24px minimum for a touch target with room to spare. */
.bio-close{position:absolute;top:0;right:0;width:44px;height:44px;
  display:flex;align-items:center;justify-content:center;
  background:var(--scarlet);color:#fff;border:0;cursor:pointer;
  line-height:1;padding:0;z-index:2}
.bio-close .pico{width:18px;height:18px;display:block}
.bio-close:hover{background:var(--royal)}

@media(max-width:820px){
  /* On a phone the panel takes nearly the whole screen. 48px of margin is right
     on a desktop, where the page behind is worth seeing; on a 390px screen it
     is 12% of the width spent on showing a blurred page nobody is reading. */
  .bio-dlg{width:calc(100vw - 20px);max-height:calc(100dvh - 28px)}

  /* Photograph on top, words beneath, and the whole panel scrolls as one — on a
     phone there isn't the height to give the text its own scrolling box without
     it becoming a letterbox two lines deep. The photograph is a fixed band
     across the top rather than a portrait column, which would otherwise push
     the words below the fold before they had started. */
  .bio-in{grid-template-columns:1fr;grid-template-rows:auto 1fr}
  /* On a phone the photo is a band across the top rather than a column beside
     the words, and 3/2 is a shape a square nearly fills — so here it still
     covers. Told to contain, a square in a 3/2 band would leave a bar of tint
     down each side of every player. */
  /* On a phone the column becomes a band across the top, so the photograph is
     a 3/2 strip and the seat, name and facts sit under it. cover here, not
     contain: 3/2 is a shape a square nearly fills, and contain would put ink
     down both sides of every player. The fixed height from the two-column
     layout has to be undone or it fights the aspect ratio. */
  .bio-side .bio-photo{height:auto;margin:0;aspect-ratio:3/2;
    background-size:cover;background-position:center}
  .bio-id{padding:18px 22px 24px}
  .bio-scroll{padding:30px 26px 34px}
  .bio-body p{font-size:16px}
  /* The bar follows the tighter padding in, so it doesn't end up sitting on the
     words. No allowance for the close button here — at this width the
     photograph is a band across the top and the button sits on that, well clear
     of the text pane, so the bar can start at the top of the words.
     It stays visible rather than being hidden for touch: with the native
     scrollbar gone there would otherwise be nothing at all to say the biography
     carries on below the fold. */
  .bio-text .bio-bar{top:30px;bottom:34px;right:11px}
}

/* ---------- history timeline ---------- */
/* ---------- timeline ----------
   Tightened throughout. Nine decades laid out at the old spacing ran to a very
   long page for something most visitors skim, so the era headings are smaller,
   the rows are closer together and the prose is a size down. The years and the
   headlines — the two things people actually scan — are untouched.

   THE RAIL AND THE DOTS
   Three measurements used to be typed in separately: the rule's position, the
   width of the year column, and each dot's offset. They disagreed, which is why
   the dots sat almost against the years and slightly off the rule. They now all
   derive from --rail and --col, and the dots are centred on the rail with a
   translate rather than by a hand-worked offset, so a dot cannot drift off the
   line and the gap after the year is whatever --rail minus --col says it is. */
.era{margin-bottom:40px}
.era-head{margin-bottom:18px}

/* The heading IS the control, so it takes the whole width — a decade is folded
   by pressing its name, not by finding a small arrow at one end. The rule that
   was on .era-head moves onto the button, which is the thing being pressed. */
.era-toggle{width:100%;display:flex;align-items:baseline;gap:16px;
  background:none;border:0;border-bottom:2px solid var(--line);
  padding:0 0 11px;margin:0;cursor:pointer;text-align:left;color:inherit;
  font:inherit}
.era-toggle:hover{border-bottom-color:var(--gold)}
.era-head b{font-weight:900;font-size:clamp(25px,3.2vw,34px);color:var(--scarlet);line-height:1}
.era-head span{font-weight:700;font-size:12px;letter-spacing:.14em;text-transform:uppercase;
  color:var(--mute);flex:1 1 auto}

/* The open/shut mark. A triangle turned rather than two different characters,
   so it rotates instead of jumping, and the transition is on transform alone,
   which costs no layout. Generated content is not in the accessibility tree,
   and aria-expanded on the button already says this properly. */
.era-toggle::after{content:'';width:0;height:0;flex:0 0 auto;align-self:center;
  border-left:6px solid transparent;border-right:6px solid transparent;
  border-top:7px solid var(--scarlet);transition:transform .2s ease}
.era-toggle[aria-expanded=false]::after{transform:rotate(-90deg)}
.era-toggle[aria-expanded=false]{border-bottom-color:var(--line)}
@media(prefers-reduced-motion:reduce){.era-toggle::after{transition:none}}

/* ---------- the timeline's own scrolling box ----------
   HOW TALL, AND WHY
   clamp(360px, 62vh, 640px). The floor stops the box collapsing to a slot on a
   short laptop screen; 360px is four rows, which is enough to read as a list
   rather than a peephole. The ceiling stops it swallowing a tall monitor, where
   62vh would be most of a metre of timeline and we are back to the problem this
   solves. In between, roughly two thirds of the screen, so the honours board
   below is always in sight and the reader can tell there is more page.

   SCROLL CHAINING IS LEFT ALONE
   No overscroll-behavior here, on purpose. The default chains: the wheel scrolls
   the box until it reaches the end, then carries on scrolling the page. Setting
   `contain` would seal the box and strand anyone whose pointer happened to be
   over it. Setting `none` does the same. The default is the behaviour we want.

   PADDING
   Room on the right for our scrollbar, and a little at the foot so the last
   entry does not sit hard against the edge. The left padding is only there to
   stop a focus ring being clipped by overflow. */
.tl-box{position:relative}
.tl-scroll{max-height:clamp(360px,62vh,640px);overflow-y:auto;
  padding:2px 40px 8px 2px;scroll-behavior:smooth}
.tl-scroll:focus{outline:none}
.tl-scroll:focus-visible{outline:2px solid var(--scarlet);outline-offset:3px}
@media(prefers-reduced-motion:reduce){.tl-scroll{scroll-behavior:auto}}

/* The native bar is hidden only once site.js has drawn ours — the attribute is
   set by the script. With scripts off the ordinary scrollbar stays, because a
   box that scrolls with nothing to show for it is a trap. */
.tl-scroll[data-own-bar]{scrollbar-width:none;-ms-overflow-style:none}
.tl-scroll[data-own-bar]::-webkit-scrollbar{display:none}

/* Same bar as the biography panel, same measurements, drawn by the same
   function. Inset 2px top and bottom so it reads as a bar in the box rather
   than a border on it. */
.tl-box .tl-bar{position:absolute;top:2px;bottom:8px;right:8px;width:4px;
  background:var(--line);z-index:4;cursor:pointer}
.tl-box .tl-thumb{position:absolute;left:-2px;right:-2px;top:0;
  background:var(--scarlet);will-change:transform;transition:background .15s}
.tl-bar:hover .tl-thumb,.tl-bar.dragging .tl-thumb{background:var(--gold)}

/* The decade heading pins to the top of the box as its entries pass beneath, so
   you always know which decade you are reading. It needs an opaque background to
   do that — the section is sec-tint, hence --tint — and it has to sit above the
   rail and the squares, which are z-index 1. The negative top margin and the
   matching padding give the heading something to cover the rail with as a row
   slides under it. */
.tl-box .era-head{position:sticky;top:0;z-index:3;background:var(--tint);
  margin:-2px 0 18px;padding:2px 0 0}
.tl-box .era{margin-bottom:34px}
.tl-box .era:last-child{margin-bottom:0}

/* ---- the timeline on a phone ----
   The box comes off entirely. A box that scrolls inside a page that also scrolls
   is a fight on a touch screen: a swipe meant for the page gets eaten by the
   timeline, and the reader has to find somewhere else on the screen to push. On
   a mouse this never comes up, because a wheel over a box is unambiguous.

   What replaces it is better anyway. site.js starts every decade SHUT on a
   phone, so the timeline arrives as eight short rows — more compact than the box
   ever was — and a tap opens the one you want. Nothing is hidden: the control
   above still opens the lot.

   The sticky decade heading goes too. It has nothing to stick to now, and left
   in it would pin itself to the top of the screen underneath the header.

   THE CONDITION IS TOUCH, NOT WIDTH
   hover:none as well as a width, because the reason is the gesture and not the
   screen. A phone turned sideways is 844px wide — past any sensible phone
   breakpoint — and still has exactly the same problem. hover:none asks the right
   question: can the thing pointing at this page hover? If it cannot, it is a
   finger, and a finger cannot tell two scrolling areas apart. */
@media(max-width:700px),(hover:none){
  .tl-scroll{max-height:none;overflow:visible;padding:0}
  .tl-box .tl-bar{display:none}
  .tl-box .era-head{position:static;margin:0 0 18px;padding:0}
  .tl-box .era{margin-bottom:26px}
}

/* One control for all eight, above the timeline. */
.tl-tools{margin:0 0 30px}
.tl-toggle{font:inherit;font-weight:700;font-size:12px;letter-spacing:.1em;
  text-transform:uppercase;text-indent:.1em;
  color:var(--ink);background:var(--tint);
  border:1px solid var(--line);padding:10px calc(16px - .1em) 10px 16px;
  cursor:pointer;transition:.18s}
.tl-toggle:hover{background:var(--ink);border-color:var(--ink);color:#fff}
/* --col  width of the year column
   --rail  distance from the left edge to the vertical rule
   --pad   clear space between the rail and the start of the text
   The gap after the year is therefore --rail minus --col: 34px on desktop,
   where it used to be a negative number, which is why the dots looked stuck to
   the dates. */
.tl{--col:62px;--rail:96px;--pad:22px;list-style:none;margin:0;padding:0;position:relative}
.tl::before{content:'';position:absolute;left:var(--rail);top:5px;bottom:5px;width:2px;
  background:var(--line);transform:translateX(-50%)}
.tl li{position:relative;display:grid;
  grid-template-columns:var(--col) 1fr;
  column-gap:calc(var(--rail) - var(--col) + var(--pad));
  padding:0 0 17px}
.tl li:last-child{padding-bottom:0}
.tl .yr{font-weight:900;font-size:17px;color:var(--ink);text-align:right;padding-top:1px}
.tl .ev{position:relative}
/* The text starts --pad to the right of the rail, so the rail is --pad to the
   left of the text — and the dot centres on it. One number, no drift. */
/* SQUARES, and two of them rather than two colours.

   These were circles, gold for an ordinary entry and scarlet for a turning
   point. Two problems with that. Round corners are against the brand, which is
   square throughout. And gold against scarlet reads as two CATEGORIES of thing —
   both are brand colours, both are saturated, neither looks subordinate to the
   other — when what is actually being said is that one matters more than the
   other. Fourteen of the twenty-eight are turning points and nothing told the
   reader that, so the pattern looked arbitrary.

   Gold for an ordinary entry, scarlet and larger for a turning point. The pale
   rail colour was tried for the ordinary ones — quieter, and it made the
   hierarchy unarguable — but it drains the rail of the brand and reads as
   unfinished. Gold against scarlet with a size difference carries the same
   meaning and looks like the rest of the site. */
.tl .ev::before{content:'';position:absolute;left:calc(var(--pad) * -1);
  top:9px;width:9px;height:9px;transform:translateX(-50%);
  border-radius:0;background:var(--gold);z-index:1}
.tl .ev.major::before{background:var(--scarlet);width:14px;height:14px;top:6px}
.tl .ev b{display:block;font-weight:700;font-size:15.5px;margin-bottom:2px}
.tl .ev p{margin:0;font-size:14px;line-height:1.55;color:var(--mute);max-width:66ch}
.tl .ev cite{font-style:normal;display:block;font-size:13px;color:var(--mute);margin-top:4px}

/* ---------- honours board ---------- */
.honours{display:grid;grid-template-columns:repeat(2,1fr);gap:2px;background:rgba(255,255,255,.28)}
.hon{background:var(--scarlet);padding:26px 28px}
.hon b{display:block;font-weight:900;font-size:15px;letter-spacing:.1em;text-transform:uppercase;
  color:#fff;margin-bottom:12px}
.hon .yrs{display:flex;flex-wrap:wrap;gap:8px}
.hon .yrs span{font-weight:700;font-size:14px;background:rgba(0,0,0,.2);color:#fff;
  padding:5px 11px;border-radius:0}
.hon i{font-style:normal;display:block;font-size:13.5px;color:rgba(255,255,255,.85);margin-top:10px}

/* ---------- the names ---------- */
.names{display:grid;grid-template-columns:repeat(3,1fr);gap:2px;background:var(--line)}
.nm{background:#fff;padding:22px 24px}
.nm b{display:block;font-weight:700;font-size:16px;margin-bottom:4px}
.nm span{font-size:13.5px;color:var(--mute);letter-spacing:.04em}

/* ---------- the team ---------- */
.teams{display:grid;grid-template-columns:repeat(3,1fr);gap:34px}
.team-group h3{font-size:14px;text-transform:uppercase;letter-spacing:.14em;
  color:var(--scarlet);margin-bottom:6px}
.team-group .cond{grid-template-columns:1fr;gap:2px;padding:14px 0}
.team-group .cond dt{font-size:12px;letter-spacing:.1em;text-transform:uppercase;
  color:var(--mute)}
.team-group .cond dd{font-weight:700;font-size:16px}
.team-group .cond dd span{font-weight:500}
.team-group .cond dd a{color:var(--scarlet);text-decoration:none;font-size:13px}
.team-group .cond dd a:hover{text-decoration:underline}
/* ---------- what's on reel ----------
   The homepage shows dates as a horizontal reel of picture cards; What's On keeps
   the plain list, which is better for scanning twenty dates. Scroll-snap does the
   paging, so there's no carousel library and it still works with the script off.
   Square corners throughout, per the brand. */
.reel-wrap{position:relative}
.reel{display:flex;gap:22px;overflow-x:auto;scroll-snap-type:x mandatory;
  scroll-behavior:smooth;padding:4px 0 20px;
  scrollbar-width:thin;scrollbar-color:var(--line) transparent}
.reel::-webkit-scrollbar{height:6px}
.reel::-webkit-scrollbar-thumb{background:var(--line)}
.reel-card{flex:0 0 316px;scroll-snap-align:start;display:flex;flex-direction:column;
  text-decoration:none;color:var(--ink);background:var(--paper);
  border:1px solid var(--line);transition:.18s}
.reel-card:hover{transform:translateY(-3px);box-shadow:0 14px 34px rgba(20,16,15,.12);
  border-color:var(--scarlet)}
.reel-img{position:relative;height:186px;background-size:cover;background-position:center;
  background-color:var(--ink-2)}
/* Date block sits on the image, scarlet so it reads over any photograph. */
.reel-date{position:absolute;left:0;bottom:0;background:var(--scarlet);color:#fff;
  padding:9px 14px 8px;text-align:center;border-top:4px solid var(--gold)}
.reel-date b{display:block;font-weight:900;font-size:26px;line-height:1}
.reel-date i{font-style:normal;display:block;font-weight:700;font-size:11px;
  letter-spacing:.14em;text-indent:.14em;text-transform:uppercase;margin-top:2px}
.reel-body{padding:20px 22px 22px;display:flex;flex-direction:column;flex:1}
.reel-body h3{font-size:19px;line-height:1.2;margin:10px 0 8px}
/* When and where are two different facts and now look like it: the date in ink
   and bold, the address grey and lighter underneath, with air between them.
   Previously both were the same 14px grey with no gap and they read as one
   run-on line. */
.reel-meta{font-size:14px;margin:0 0 16px}
.reel-meta span{display:block}
.reel-meta .when{font-weight:700;color:var(--ink);letter-spacing:.01em}
.reel-meta .where{color:var(--mute);font-size:13.5px;margin-top:4px;line-height:1.45}
.reel-body .more{margin-top:auto;font-weight:700;font-size:12.5px;letter-spacing:.1em;
  text-transform:uppercase;color:var(--scarlet)}
.reel-card .ev-note{margin-top:auto;font-size:13.5px;color:var(--mute)}
/* ---- reel controls ----
   The native scrollbar is hidden and replaced with our own, so the track and
   thumb can be square-cornered and in brand colours like everything else. */
.reel{scrollbar-width:none;-ms-overflow-style:none}
.reel::-webkit-scrollbar{display:none}
/* While the thumb is being dragged the snap points have to come off. Left on,
   the browser re-snaps to a card boundary on every pointer move and the reel
   stutters instead of following the cursor. Snap returns on release, so it
   still settles neatly on a card. */
.reel.dragging{scroll-snap-type:none;scroll-behavior:auto;cursor:grabbing}

/* This was gold and 7px, matching the rule under the header, on the theory that
   it would read as the brand mark rather than browser furniture. It did — and
   that was the problem. A 7px bar in the header's exact weight, carrying a gold
   segment, looks like a brand rule that has failed to finish drawing rather than
   something you can drag.

   The thumb stays Sovereign Gold. It is the band's colour and this is the band's
   scrollbar; that was the original intent and it stands.

   NOTE, left as it is on purpose: gold on this track measures 1.23:1, where
   WCAG 1.4.11 asks 3:1 for the visible boundary of a control. It is recorded
   here rather than silently "fixed", because the row does not depend on the bar
   — arrows, wheel, touch, keyboard and the cards themselves all work without it,
   so it reports position rather than granting access. If it ever has to pass,
   darken the TRACK; the thumb stays gold. */
/* No margin of its own. The reel above already carries 20px of bottom padding —
   room for the shadow a card casts when it lifts on hover, which would otherwise
   be clipped by the scroller. That padding is invisible, so adding a further
   12px here set the scrollbar 32px adrift from the row it belongs to while
   reading in the stylesheet as though it were 12. */
/* Scrollbar and arrows on one line — the two controls for the row, together.
   The bar takes whatever width is left; the arrows are a fixed size at the end
   of it. */
.reel-foot{margin-top:0;display:flex;align-items:center;gap:20px}
.reel-track{flex:1 1 auto;height:4px;background:var(--line);position:relative;cursor:pointer}
.reel-thumb{position:absolute;top:0;bottom:0;left:0;min-width:44px;
  background:var(--gold);will-change:transform;transition:background .15s}
.reel-track:hover .reel-thumb,.reel-thumb:active{background:#ffdf5e}

/* Arrows live in the section header, top right, beside the "all dates" link.
   That's what Reuters and Spotify do for a row of cards, and it's better than
   floating them over the artwork: they never cover a picture, never sit at an
   arbitrary height, and read as controls for the row rather than as something
   attached to one card. */
.reel-nav{display:flex;gap:8px;flex:0 0 auto}
.reel-nav button{width:42px;height:42px;padding:0;display:grid;place-items:center;
  border:1px solid var(--line);background:var(--paper);color:var(--ink);
  cursor:pointer;transition:.15s}
.reel-nav button svg{width:13px;height:13px;display:block}
.reel-nav button:hover:not(:disabled){background:var(--scarlet);
  border-color:var(--scarlet);color:#fff}
/* Dimmed rather than hidden at the ends — removing them would shift the link
   beside them sideways every time you reached an edge. */
.reel-nav button:disabled{opacity:.25;cursor:default}

@media(max-width:640px){.reel-card{flex-basis:82%}.reel-nav{display:none}}




@media(max-width:900px){.teams{grid-template-columns:1fr}}

/* ---------- conductors ---------- */
.conductors{border-top:1px solid var(--line)}
.cond{display:grid;grid-template-columns:170px 1fr;gap:24px;padding:18px 0;
  border-bottom:1px solid var(--line);align-items:baseline}
.cond dt{font-weight:700;font-size:14px;letter-spacing:.06em;color:var(--scarlet)}
.cond dd{margin:0;font-size:16px}
.cond dd span{display:block;font-size:13.5px;color:var(--mute);margin-top:2px}

@media(max-width:900px){
  .honours,.names{grid-template-columns:1fr}
}
@media(max-width:640px){
  /* Everything follows from the three variables now — no separate offsets to
     keep in step. */
  .tl{--col:46px;--rail:70px;--pad:17px}
  .tl .yr{font-size:15px}
  .cond{grid-template-columns:1fr;gap:2px}
}

/* ---------- quote ----------
   BRAND RULE: two scarlet surfaces never sit next to each other. This band sits
   between the honours board and the closing ask, both scarlet, so it must not be
   a third. It used to be flat tint, which did the job but looked like nothing at
   all. A photograph does the same job and earns its place.

   The photograph is the background; the words sit on a solid panel over it. Not
   straight on the picture, because white text on a stage shot is legible with
   THIS image and a gamble with the next one anybody swaps in. The panel keeps
   the contrast fixed at 17:1 whatever the photograph does. */
.quote{position:relative;background:var(--ink-2);color:var(--ink);overflow:hidden}
/* Deliberately taller than its contents, and overhanging top and bottom, so the
   photograph can drift against the scroll without ever showing an edge. The
   overhang is what makes the parallax possible; 14% of a 560px section is about
   78px of slack each way, and site.js never moves it more than 54px. */
.quote-photo{position:absolute;inset:-14% 0;background-size:cover;
  background-position:center 38%;background-repeat:no-repeat;
  will-change:transform}
/* An even wash now the panel is centred: weighting it to one side only made
   sense when the panel sat on that side. Slightly deeper top and bottom so the
   photograph settles behind the card rather than competing with it. */
.quote-photo::after{content:'';position:absolute;inset:0;
  background:linear-gradient(180deg,rgba(20,16,15,.50) 0%,rgba(20,16,15,.34) 40%,
                                    rgba(20,16,15,.34) 60%,rgba(20,16,15,.52) 100%)}
.quote-in{position:relative;display:flex;align-items:center;justify-content:center;
  min-height:600px;padding:88px 24px}
/* Centred, and built like the rest of the site: square, gold rule across the
   top, kicker and heading in the house order. */
.quote-card{background:var(--tint);max-width:640px;margin:0 auto;text-align:center;
  padding:44px 52px 38px;border-top:7px solid var(--gold);
  box-shadow:0 24px 60px rgba(20,16,15,.30)}
/* The crest, bottom left, exactly as on every other surface: no size override,
   so it takes the standard 'auto 100%' and fills the card top to bottom.
   It was held back to 72% on the argument that a full-height crest would be more
   than half the width of the card and stop being a watermark. That was wrong on
   both counts — it is a watermark because of its colour, not its size, and
   holding it back is what made it read as a small graphic parked in the corner
   rather than part of the surface. The card's children are lifted above it by
   the .mark rule, so nothing about the text has to change. */
.quote-card .kicker{margin-bottom:10px}
.quote-card h2{font-size:clamp(24px,3vw,34px);margin-bottom:30px}
/* An oversized opening mark, in gold, above the words. */
.qmark{font-weight:900;font-size:58px;line-height:.7;color:var(--gold);
  margin:0 0 14px}

/* All the quotes occupy the same grid cell, so the section is as tall as the
   longest one and nothing jumps as they change. Only the current one is visible. */
.quote-stack{display:grid}
.quote-stack>figure{grid-area:1/1;margin:0;opacity:0;visibility:hidden;
  transition:opacity .5s ease}
.quote-stack>figure.on{opacity:1;visibility:visible}
/* Bold rather than Black — a spoken sentence, not a headline. */
/* Ink, not scarlet. Someone else's words carry themselves; setting them in the
   brand colour made the band look like it was shouting its own praise, and put
   a third red surface into the lower third of the homepage. Grey does the
   attribution underneath, so the whole element is black-and-grey. */
/* A size down from before: the panel is narrower than the old full-width band,
   and 33px in a 600px box gives four words a line. */
.quote blockquote{font-weight:700;font-size:clamp(19px,2.1vw,26px);line-height:1.35;
  margin:0 0 20px;color:var(--ink)}
/* A short gold rule between the words and whoever said them. inline-block so the
   rule is only as wide as the name it sits above, and centres with the card. */
.quote figcaption{font-weight:700;font-size:13px;letter-spacing:.1em;
  text-transform:uppercase;padding-top:16px;border-top:3px solid var(--gold);
  display:inline-block}
.quote figcaption span{display:block;font-weight:500;text-transform:none;
  letter-spacing:0;font-size:13.5px;color:var(--mute);margin-top:4px}

.quote-dots{display:flex;gap:9px;justify-content:center;margin-top:26px}
.quote-dots button{width:9px;height:9px;padding:0;border:0;background:var(--line);
  cursor:pointer;transition:background .2s}
.quote-dots button[aria-current=true]{background:var(--ink)}
.quote-dots button:hover{background:var(--mute)}

/* Anyone who has asked for less movement gets the quotes without the crossfade;
   site.js also stops advancing them on its own. */
@media(prefers-reduced-motion:reduce){.quote-stack>figure{transition:none}}

/* On a narrow screen there isn't room to sit a readable panel on top of a
   photograph, so the two stop overlapping and stack: picture, then words. The
   photograph comes out of absolute positioning and becomes a band of its own. */
@media(max-width:820px){
  .quote-photo{position:relative;height:230px}
  .quote-photo::after{background:linear-gradient(180deg,rgba(20,16,15,.20),rgba(20,16,15,.35))}
  .quote-in{min-height:0;padding:0}
  .quote-card{max-width:none;width:100%;padding:32px 26px 28px;box-shadow:none}
  .qmark{font-size:48px}
}

/* ---------- reveal on scroll ----------
   THE ONE RULE HERE: nothing is ever hidden unless JavaScript is definitely
   running AND the reader hasn't asked for less movement. Every rule below is
   behind .js-anim, which is added to <html> by a one-line script in the head of
   the page. Scripts off, script failed, reduced motion — the class is never
   added and the whole file below does nothing. The page is simply visible,
   which is the only acceptable failure mode: content that needs JavaScript to
   appear is content that sometimes doesn't.

   The class goes on in the HEAD rather than from site.js at the end of the body.
   From the end of the body you get a frame of visible content that then vanishes
   and fades back in — a flicker on every load. */
.js-anim [data-rise]{opacity:0;transform:translateY(24px);
  transition:opacity .75s cubic-bezier(.22,.61,.36,1),
             transform .75s cubic-bezier(.22,.61,.36,1)}
.js-anim [data-rise].in{opacity:1;transform:none}

/* A group whose children come in one after another. site.js writes the delay
   onto each child; the CSS just has to not fight it. */
.js-anim [data-rise-stagger]>*{opacity:0;transform:translateY(24px);
  transition:opacity .7s cubic-bezier(.22,.61,.36,1),
             transform .7s cubic-bezier(.22,.61,.36,1)}
.js-anim [data-rise-stagger].in>*{opacity:1;transform:none}

/* ---- the hero, on load ------------------------------------------------------
   The one part of the page that moves without being scrolled to, because it is
   already there when the page opens. Each line follows the one above it, so the
   band's name arrives before the sentence explaining it, which arrives before
   the buttons. That order is the point: it's the reading order, drawn.

   .hero-in is given .in by site.js on the first painted frame — not by an
   observer, which would be answering a question we already know the answer to. */
.js-anim .hero-in>*{opacity:0;transform:translateY(28px);
  transition:opacity .8s ease,transform .9s cubic-bezier(.22,.61,.36,1)}
.js-anim .hero-in.in>*{opacity:1;transform:none}
.js-anim .hero-in>*:nth-child(1){transition-delay:.10s}
.js-anim .hero-in>*:nth-child(2){transition-delay:.22s}
.js-anim .hero-in>*:nth-child(3){transition-delay:.34s}
.js-anim .hero-in>*:nth-child(4){transition-delay:.46s}
/* The gold bar under the headline draws itself once the words are up. */
.js-anim .hero .rule::after{transform:scaleX(0);transform-origin:left;
  transition:transform .9s cubic-bezier(.22,.61,.36,1) .5s}
.js-anim .hero-in.in .rule::after{transform:scaleX(1)}

/* ---- the detailed reveal ----------------------------------------------------
   [data-reveal] is a trigger, not an effect: it has no appearance of its own and
   never moves. It simply gains .in when it arrives, and the parts inside it —
   the kicker, the heading word by word, the gold bar drawing itself, then the
   line underneath — come in one after another off that single class.

   One observer per block rather than one per word. Forty separate observers for
   the words of five headings would be forty callbacks on every scroll for no
   visible gain.

   EASING: everything here uses the same curve as the block reveals, so the page
   has one sense of movement rather than several competing ones. */
.js-anim [data-reveal] .kicker{opacity:0;transform:translateY(12px);
  transition:opacity .5s ease,transform .5s cubic-bezier(.22,.61,.36,1)}
.js-anim [data-reveal].in .kicker{opacity:1;transform:none}

/* One word at a time. The rise is in em, so it scales with the heading — a
   48px headline and a 22px one lift by the same proportion, not the same pixels. */
.js-anim [data-reveal] .w{display:inline-block;opacity:0;transform:translateY(.6em);
  transition:opacity .5s ease,transform .6s cubic-bezier(.22,.61,.36,1)}
.js-anim [data-reveal].in .w{opacity:1;transform:none}

/* The gold bar draws itself from the left, after the words have landed. scaleX
   rather than width: a transform doesn't touch layout, so nothing round it
   reflows sixty times a second while it grows. Centred headings draw from the
   middle outwards, or the bar would slide off its own centre. */
.js-anim [data-reveal] .rule::after{transform:scaleX(0);transform-origin:left;
  transition:transform .75s cubic-bezier(.22,.61,.36,1) .38s}
.js-anim [data-reveal].in .rule::after{transform:scaleX(1)}

/* The line under the heading, last of all — and on the quote card, the mark,
   the words and the dots follow the same beat.

   Direct-child paragraphs are included so the standard kicker / heading / line
   block works everywhere without hand-marking each one. The kicker is itself a
   <p>, so it has to be excluded or it would be caught twice and take the later
   rule's delay, arriving after the heading instead of before it. */
.js-anim [data-reveal] > p:not(.kicker),
.js-anim [data-reveal] .after,
.js-anim [data-reveal] .qmark,
.js-anim [data-reveal] .quote-stack,
.js-anim [data-reveal] .quote-dots{opacity:0;transform:translateY(14px);
  transition:opacity .55s ease .42s,transform .55s cubic-bezier(.22,.61,.36,1) .42s}
.js-anim [data-reveal].in > p:not(.kicker),
.js-anim [data-reveal].in .after,
.js-anim [data-reveal].in .qmark,
.js-anim [data-reveal].in .quote-stack,
.js-anim [data-reveal].in .quote-dots{opacity:1;transform:none}
.js-anim [data-reveal] .quote-stack{transition-delay:.5s}
.js-anim [data-reveal] .quote-dots{transition-delay:.58s}

/* Photographs settle rather than simply appear: a shade over-size to begin with,
   easing back to true as the card arrives. Slower than everything else on
   purpose — a picture that snaps looks cheap. The parent must clip, or the
   oversized image spills past the card's border while it settles. */
.card,.reel-card{overflow:hidden}
.js-anim [data-rise] .card-img,.js-anim [data-rise-stagger] .card-img,
.js-anim [data-rise] .reel-img,.js-anim [data-rise-stagger] .reel-img{
  transform:scale(1.07);transition:transform 1.2s cubic-bezier(.22,.61,.36,1)}
.js-anim [data-rise].in .card-img,.js-anim [data-rise-stagger].in .card-img,
.js-anim [data-rise].in .reel-img,.js-anim [data-rise-stagger].in .reel-img{
  transform:none}

/* Belt and braces. If .js-anim ever gets added on a machine that has since been
   told to reduce motion, this still stops the movement. */
@media(prefers-reduced-motion:reduce){
  .js-anim [data-rise],.js-anim [data-rise-stagger]>*,
  .js-anim [data-reveal] .kicker,.js-anim [data-reveal] .w,
  .js-anim [data-reveal] > p,
  .js-anim [data-reveal] .after,.js-anim [data-reveal] .qmark,
  .js-anim [data-reveal] .quote-stack,.js-anim [data-reveal] .quote-dots,
  .js-anim .card-img,.js-anim .reel-img,.js-anim .hero-in>*{
    opacity:1;transform:none;transition:none}
  .js-anim [data-reveal] .rule::after{transform:none;transition:none}
  .quote-photo,.hero-img{transform:none!important}
}

/* ---------- forms ---------- */
.form{display:grid;gap:14px}
.form label{font-weight:700;font-size:12px;letter-spacing:.1em;text-transform:uppercase;
  color:var(--mute);margin-bottom:-8px}
.dark .form label{color:rgba(255,255,255,.65)}
.form input,.form select,.form textarea{padding:14px 16px;border:2px solid var(--line);
  background:#fff;font-family:inherit;font-size:16px;border-radius:0;color:var(--ink)}
.dark .form input,.dark .form select,.dark .form textarea{
  background:rgba(255,255,255,.06);border-color:rgba(255,255,255,.24);color:#fff}
.dark .form input::placeholder,.dark .form textarea::placeholder{color:rgba(255,255,255,.5)}
.form input:focus,.form select:focus,.form textarea:focus{border-color:var(--gold);outline:none}
.form .row{display:grid;grid-template-columns:1fr 1fr;gap:14px}
.form-ok{background:var(--gold);color:var(--ink);padding:18px 20px;font-weight:700}

/* ---------- tracks ---------- */
.tracks{border:1px solid var(--line);padding:26px}
.track{display:grid;grid-template-columns:auto 1fr;gap:16px;align-items:center;padding:14px 0;
  border-bottom:1px solid var(--line)}
.track:last-child{border-bottom:0}
/* Royal Red, matching the button beside them. Changed everywhere rather than
   only on the scarlet section — the player should look the same on every page.
   Hover goes to ink for the same reason .btn-royal does: royal has nowhere
   redder to move to. Gold still marks the one that's playing. */
/* The mark inside is a drawn SVG, not a character — see ICON_PLAY in site.js for
   why. Sized here rather than by font-size, which no longer has anything to act
   on. */
.play{width:44px;height:44px;border-radius:50%;border:0;background:var(--royal);color:#fff;
  cursor:pointer;display:grid;place-items:center;transition:.15s}
.play .pico{width:17px;height:17px;display:block}
.play-lg .pico{width:27px;height:27px}
.play:hover{background:var(--ink);transform:scale(1.07)}
.play.on{background:var(--gold);color:var(--ink)}
.track b{display:block;font-weight:700;font-size:15.5px}
.track span{font-size:13px;color:var(--mute)}

/* On a scarlet section the track list becomes a white panel rather than being
   restyled piece by piece. Everything inside then falls back to its normal
   colours — ink titles, muted credits, the scarlet play button — so there is
   one override here instead of six, and the player looks the same wherever it
   appears. color has to be reset too: .red sets white on the whole section. */
.red .tracks{background:var(--paper);color:var(--ink);border-color:var(--paper)}

/* ---------- our music: the featured listen ----------
   The page's first job is to answer "what do they sound like?", so one track
   is played large before anything is asked of the visitor. It reuses .track so
   the markup and the audio wiring stay identical to the list underneath — only
   the scale changes. */

.feature{grid-template-columns:auto 1fr;gap:26px;padding:30px;border:1px solid var(--line);
  background:var(--tint);align-items:center}
.feature b{font-size:clamp(21px,2.6vw,30px);font-weight:900;letter-spacing:.01em;
  line-height:1.1;margin-bottom:6px}
.feature span{font-size:15px}
.play-lg{width:74px;height:74px}
@media(max-width:560px){
  .feature{padding:22px;gap:18px}
  .play-lg{width:56px;height:56px}
  .play-lg .pico{width:21px;height:21px}
}

/* The list sits directly beneath the feature, so it loses its own top border
   and reads as a continuation of it rather than a second, separate panel. */
.after-feature{border-top:0;margin-top:0}

/* ---------- our music: records ----------
   Works in both states. While the record is unreleased the card is an
   announcement; once it's out the same card carries a price and a button. */

.albums{display:grid;gap:30px}
.album{display:grid;grid-template-columns:230px 1fr;gap:34px;align-items:center}
.album h3{font-size:clamp(22px,2.6vw,31px);font-weight:900;line-height:1.1;margin:6px 0 12px}
.album-in p{margin:0}
.album-buy{display:flex;align-items:center;gap:18px;margin-top:20px}
.album-buy b{font-size:23px;font-weight:900}
.album-soon{margin-top:18px;font-size:14px;font-weight:700;letter-spacing:.05em;
  text-transform:uppercase;color:var(--gold)}
@media(max-width:720px){
  .album{grid-template-columns:1fr;gap:22px}
}

/* A built sleeve for records with no artwork yet — square, scarlet, gold rule.
   Deliberately not a mock CD case: it reads as a placeholder that happens to
   be handsome, rather than pretending to be a photograph of a product. */
.sleeve{display:grid;align-content:center;gap:10px;aspect-ratio:1;padding:26px;
  background:var(--scarlet);border-bottom:6px solid var(--gold);container-type:inline-size}
/* White, not gold: at this size the label is small text, and gold on scarlet
   only reaches 3.75:1. White clears AA at 6.17:1. The gold stays on the rule
   and the base edge, where contrast rules don't apply. */
.sleeve em{font-style:normal;font-weight:700;font-size:4.6cqw;letter-spacing:.16em;
  text-transform:uppercase;color:#fff}
.sleeve b{font-weight:900;font-size:11cqw;line-height:1.02;color:#fff;text-transform:uppercase}
.sleeve i{display:block;width:26%;height:5px;background:var(--gold);margin-top:4px}
.sleeve-art{width:100%;aspect-ratio:1;object-fit:cover;display:block}

/* ---------- what's on: the poster wall ----------
   The frame is 4:5. The band's exports vary — 900x1300 (1:1.444) and 945x1181
   (1:1.250) have both turned up — so posters are MOUNTED in it rather than
   cropped to it. On a concert poster the date, venue and ticket line ARE the
   artwork, and cropping takes the scarlet foot carrying all three.

   Where there's no poster the card builds one from the fixture data in the same
   layout — masthead, title, scarlet footer — so the wall reads evenly whether
   the artwork exists or not. A built poster has one advantage over a real one:
   it's text, so it can be read aloud and indexed. A supplied poster is a
   picture, which is why those carry a full alt description instead.

   Sizes are in cqw — a percentage of the CARD's width, not the viewport — so a
   built poster keeps its proportions at any column count. */
/* A line of orientation between the next-performance bar and the wall, so the
   posters don't start cold. Two columns: what's coming, and how tickets work. */
.wall-intro{display:grid;grid-template-columns:1.15fr 1fr;gap:52px;
  margin-bottom:46px;align-items:start}
.wall-intro p{margin:0}
.wall-intro p+p{font-size:15.5px;color:var(--mute);line-height:1.65}
.wall-intro p+p b{color:var(--ink);font-weight:700}
/* The summary sits under the lede in the same column, a size down from it and a
   size up from the running text on the right — it is the second thing read on
   the page, not the third. Empty until site.js writes it, and an empty paragraph
   would otherwise leave a hole where its margin is. */
/* The summary of the season. It used to sit under the lede in the left column,
   with a paragraph about how to buy tickets alongside it. That paragraph has
   gone, so this now takes the right-hand column on its own — which suits it:
   the lede states the shape of the season and this fills it in.

   The selector names .wall-intro deliberately. Without it, `.wall-intro p+p`
   wins on specificity and greys this down to the size the departed paragraph
   used — small print. It is not small print: it is what the page is about, and
   the only thing on the page telling anybody what is actually coming up. */
.season-sum{margin:14px 0 0;font-size:16.5px;line-height:1.55;color:var(--ink);
  text-align:justify;-webkit-hyphens:auto;hyphens:auto;hyphenate-limit-chars:8 4 4}
.wall-intro p.season-sum{margin:0;font-size:16.5px;color:var(--ink)}
.season-sum:empty{display:none}

@media(max-width:820px){.wall-intro{grid-template-columns:1fr;gap:22px}}

.wall{display:grid;grid-template-columns:repeat(3,1fr);gap:26px}

/* Month headings run the full width of the grid and break the wall into a
   season rather than a pile. The gold rule stretches to fill whatever is left
   after the month name, so it sets its own length — the same device as the
   underlines, but earning its keep as a divider. */
.wall-head{grid-column:1/-1;display:flex;align-items:center;gap:18px;margin-top:24px}
.wall-head:first-child{margin-top:0}
.wall-head b{font-weight:900;font-size:clamp(22px,2.7vw,32px);line-height:1;
  text-transform:uppercase;white-space:nowrap}
.wall-head u{text-decoration:none;font-weight:700;font-size:15px;color:var(--mute);
  white-space:nowrap}
/* The gold rule now runs to the end of the row — there is nothing after it to
   leave room for, since the date count that used to sit there has gone. */
.wall-head em{flex:1;height:4px;background:var(--gold);font-style:normal;min-width:20px}

/* The next fixture gets a flag. One per page, so it reads as "this is the one
   coming up" rather than as decoration. */
.poster-next{position:absolute;top:0;left:0;z-index:2;background:var(--gold);
  color:var(--ink);font-weight:900;font-size:3cqw;letter-spacing:.16em;
  text-transform:uppercase;padding:2.4cqw 4.4cqw;line-height:1}

@media(max-width:560px){.wall-head b{font-size:24px}}

.poster{container-type:inline-size;display:block;text-decoration:none;color:inherit;
  position:relative;aspect-ratio:4/5;overflow:hidden;background:var(--ink);
  transition:.18s}
.poster:hover{transform:translateY(-3px);box-shadow:0 16px 40px rgba(20,16,15,.22)}

/* A supplied poster is MOUNTED, not cropped. The band's exports aren't a single
   ratio — two of the three seen so far are 900x1300 (1:1.444), the third is
   945x1181 (1:1.250) — so any fixed frame would trim something. object-fit:cover
   would crop, and on a concert poster the first thing lost is the scarlet foot
   carrying the date and the ticket URL. contain keeps every poster whole and
   lets the ink show as a mount around it, which reads as framing rather than as
   a mistake. */
.poster-art{width:100%;height:100%;object-fit:contain;display:block;background:var(--ink)}

/* A built one, echoing the house layout. */
.poster-photo{position:absolute;inset:0;background-size:cover;background-position:center;
  background-color:var(--ink-2)}
.poster-scrim{position:absolute;inset:0;
  background:linear-gradient(180deg,rgba(20,16,15,.78) 0%,rgba(20,16,15,.30) 32%,
                                    rgba(20,16,15,.35) 58%,rgba(20,16,15,.88) 78%)}
.poster-in{position:relative;height:100%;display:flex;flex-direction:column;
  color:#fff;text-align:center}

.poster-mast{padding:5cqw 5cqw 0}
.poster-mast u{text-decoration:none;display:block;font-weight:500;font-size:4.4cqw;
  letter-spacing:.02em}
.poster-mast b{display:block;font-weight:900;font-size:10cqw;line-height:1;
  color:var(--gold);letter-spacing:.01em}
.poster-mast i{font-style:normal;display:block;font-weight:900;font-size:3.7cqw;
  letter-spacing:.1em;margin-top:1cqw}

.poster-title{margin-top:auto;padding:0 5cqw 4cqw;font-weight:900;font-size:8.4cqw;
  line-height:.98;text-transform:uppercase;text-wrap:balance}

/* The scarlet foot, as on the printed posters: crest, gold rule, then details.

   ITS HEIGHT IS FIXED, and that is the point of this block. It used to be
   whatever its contents came to, so a card for "Holy Trinity Parish Church, High
   St, Rothwell" carried a visibly deeper red band than one for "Northampton &
   County Club" — same wall, same size cards, different proportions. Set to
   32cqw, which on a 4:5 card is a touch over a quarter of its height, and every
   poster on the wall now cuts at the same line.

   The text has to fit that, so each line is held to one line and clipped with an
   ellipsis if it will not. Nothing is lost by it: the venue and the date are
   both repeated in full in the caption under the card and again in the panel
   that appears over it. The poster is a poster, not the record.

   26cqw, which is 21% of a 4:5 card. That figure is not chosen, it is measured:
   the David Read card is a poster the band supplied, its red band is part of the
   artwork, and it comes to 20.7% of the card. A built poster sitting next to a
   real one should cut at the same line. It was 34cqw and looked visibly deeper.

   Getting there meant the type had to come down with it — the four lines and
   their padding measured 31.7cqw, which will not fit in 26. Everything in here
   is scaled to 0.84 and the padding to 3cqw, which lands at 25.9. Slack is thin
   by design at that size, so overflow:hidden below is doing real work rather
   than sitting there as a formality.

   min-width:0 on the text column because a grid item will not shrink below its
   content by default, and without it the ellipsis never triggers — the column
   just pushes the card wider instead. */
.poster-foot{background:var(--scarlet);display:grid;grid-template-columns:auto 1.2cqw 1fr;
  gap:3cqw;align-items:center;padding:3cqw 5cqw;text-align:left;
  height:26cqw;box-sizing:border-box;overflow:hidden}
.poster-foot img{width:13cqw;height:auto}
.poster-foot > span:last-child{min-width:0}
.poster-bar{background:var(--gold);align-self:stretch}
.poster-town,.poster-when,.poster-where,.poster-tix{
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.poster-town{display:block;font-weight:900;font-size:6.2cqw;line-height:1;
  text-transform:uppercase}
.poster-when{display:block;font-weight:700;font-size:3.1cqw;margin-top:1.2cqw}
.poster-where{display:block;font-weight:500;font-size:2.6cqw;opacity:.9;margin-top:.5cqw}
.poster-tix{display:block;font-weight:700;font-size:2.5cqw;color:var(--gold);margin-top:1.3cqw}

/* Hover: the poster falls back and the detail comes forward.
   The blurred layer is scaled up 6% because a blur samples past the element's
   edge — without the overscan you get a soft, pale rim where there's nothing
   left to sample from. */
.poster-art,.poster-photo{transition:filter .25s ease,transform .25s ease}
.poster-in{transition:opacity .2s ease}

.poster:hover .poster-art,.poster:focus-visible .poster-art,
.poster:hover .poster-photo,.poster:focus-visible .poster-photo{
  filter:blur(7px) brightness(.5);transform:scale(1.06)}
/* A built poster carries its own type, which would show through the blur and
   collide with the overlay — so it steps aside. */
.poster:hover .poster-in,.poster:focus-visible .poster-in{opacity:0}

.poster-over{position:absolute;inset:0;display:flex;flex-direction:column;
  align-items:center;justify-content:center;text-align:center;
  padding:8cqw 7cqw;color:#fff;opacity:0;transition:opacity .25s ease;
  pointer-events:none}
.poster:hover .poster-over,.poster:focus-visible .poster-over{opacity:1}
.poster-over u{text-decoration:none;font-weight:700;font-size:3.6cqw;
  letter-spacing:.18em;text-transform:uppercase;color:var(--gold)}
.poster-over h3{font-size:8.8cqw;line-height:1.04;margin:3.2cqw 0;text-transform:uppercase;
  text-wrap:balance}
.poster-over p{margin:0;font-size:4.8cqw;line-height:1.45}
.poster-over p b{display:block;font-weight:700}
.poster-over .btn{margin-top:6cqw;font-size:4cqw;padding:4cqw 7cqw;letter-spacing:.08em}
.poster-over .ev-note{margin-top:5cqw;font-size:4cqw;color:rgba(255,255,255,.85);
  font-style:italic}

/* Caption stays as plain text under every card. It is the selectable, indexable
   copy of the details on a supplied poster — a poster is a picture, and neither
   Google nor a screen reader can read one — and it's what a touch device sees,
   since there is no hover there. No button: the whole card is the link. */
.poster-cap{padding:14px 2px 0}
.poster-cap b{display:block;font-size:15px;font-weight:700}
.poster-cap span{display:block;font-size:13.5px;color:var(--mute);font-weight:500}

/* No pointer, no hover — so on touch the detail layer never appears and the
   caption does all the work. Nothing is lost; it just isn't decorated. */
@media(hover:none){
  .poster-over{display:none}
}
@media(prefers-reduced-motion:reduce){
  .poster-art,.poster-photo,.poster-in,.poster-over{transition:none}
  .poster:hover .poster-art,.poster:hover .poster-photo{transform:none}
}

@media(max-width:900px){.wall{grid-template-columns:repeat(2,1fr)}}
@media(max-width:560px){.wall{grid-template-columns:1fr}}

/* ---------- live contest record ----------
   Built by record.js from the results feed. Square corners, scarlet rules,
   wins picked out in Royal Red so the eye can find them down a long column. */
/* ---------- the full contest record: filters ---------- */
.rt-tools{display:flex;flex-wrap:wrap;gap:16px 22px;align-items:flex-end;
  padding-bottom:20px;border-bottom:2px solid var(--ink);margin-bottom:14px}
.rt-tools label{display:flex;flex-direction:column;gap:6px;font-weight:700;font-size:11.5px;
  letter-spacing:.12em;text-transform:uppercase;color:var(--mute)}
.rt-tools select{font:inherit;font-size:15px;font-family:inherit;padding:9px 12px;
  border:2px solid var(--line);border-radius:0;background:#fff;color:var(--ink);
  min-width:200px}
.rt-tools select:focus{border-color:var(--gold);outline:none}
.rt-check{flex-direction:row!important;align-items:center;gap:9px!important;
  color:var(--ink)!important;font-size:13px!important;letter-spacing:.06em!important;
  padding-bottom:9px;cursor:pointer}
.rt-check input{width:18px;height:18px;accent-color:var(--scarlet);cursor:pointer}
.rt-clear{margin-bottom:9px;background:none;border:0;padding:0;cursor:pointer;
  font:inherit;font-weight:700;font-size:12.5px;letter-spacing:.06em;
  color:var(--scarlet);border-bottom:2px solid transparent}
.rt-clear:hover{border-color:var(--gold)}
.rt-count{margin:0 0 16px;font-size:13.5px;color:var(--mute)}
.rt-none{padding:26px 0!important;color:var(--mute);text-align:center}
.rt-foot{margin-top:22px}

.rec-table{width:100%;border-collapse:collapse;font-size:15px}
.rec-table th{text-align:left;font-weight:900;font-size:11.5px;letter-spacing:.14em;
  text-transform:uppercase;color:var(--scarlet);padding:0 16px 12px 0;
  border-bottom:2px solid var(--scarlet)}
.rec-table td{padding:12px 16px 12px 0;border-bottom:1px solid var(--line);
  vertical-align:top}
.rec-table tr:last-child td{border-bottom:0}
.rec-table td:first-child{font-weight:700;white-space:nowrap;width:64px}
.rec-table td:nth-child(3){white-space:nowrap;width:74px}
.rec-table td:last-child{color:var(--mute);white-space:nowrap}
.rt-win{color:var(--royal);font-weight:900}
@media(max-width:640px){
  .rec-table td:last-child,.rec-table th:last-child{display:none}
  .rec-table{font-size:14px}
  .rt-tools{gap:14px}
  .rt-tools label{flex:1 1 100%}
  .rt-tools select{min-width:0;width:100%}
}

/* ---------- brand mark watermark ----------
   The supplied mark, always bottom-left, bleeding off that corner.
   Solid brand colours — no opacity — exactly as the reference artwork:
       white  #FFFFFF  →  mark #F2F2F2   (light grey)
       scarlet#BE1D2E  →  mark #A50E0E   (Royal Red)
       black  #0D0D0D  →  mark #000000
   Mark is 373 × 417, so every height below is width × 1.118.
   USE IT ONCE PER PAGE. It's punctuation, not wallpaper — on the page banner
   for inner pages, and on a single chosen section for the homepage.
   Opt in with class="mark"; .page-head carries it automatically. */
.mark,.page-head{position:relative;overflow:hidden}
.mark>*,.page-head>*{position:relative;z-index:1}

/* The mark fills the section's full height — top edge flush with the top of the
   section, bottom flush with the bottom — and its width follows from that.
   'auto 100%' scales to the height and lets the width fall out proportionally,
   so it can never be short of the frame however tall the section grows. */
.mark::before,.page-head::before{
  content:'';position:absolute;pointer-events:none;z-index:0;
  inset:0;
  background-position:left bottom;
  background-size:auto 100%;
  background-repeat:no-repeat}

/* The colour follows the surface it sits on */
.mark::before                             {background-image:url('../img/gus-crest-light.png')}  /* on white   */
.red.mark::before                         {background-image:url('../img/gus-crest-red.png')}    /* on scarlet */
/* The page banners take the BLACK mark rather than the royal one. On scarlet it
   reads as a shadow in the corner instead of a second red, which is closer to
   how the crest is used elsewhere in the brand. It's a much stronger contrast
   than royal-on-scarlet, so it's held back with opacity to keep it a watermark
   rather than a graphic. */
.dark.mark::before,.foot.mark::before     {background-image:url('../img/gus-crest-dark.png')}      /* on black   */
.page-head::before{background-image:url('../img/gus-crest-dark.png')}

/* On narrow screens a full-height mark would span most of the width, so it
   backs off to three-quarters height while staying anchored bottom-left. */
@media(max-width:700px){
  .mark::before,.page-head::before{background-size:auto 75%}
}

/* ---------- gold rule under headings ----------
   The device used across the band's artwork: a Sovereign Gold bar
   sitting under the heading, the width of the text. */
/* BRAND RULE: the visible gap above the bar must equal the bar's own thickness.
   Both read from one variable so they can't drift apart.
   The -0.19em pulls out the dead space every line box carries below the cap
   baseline — Noverion's descender plus leading measures 0.189em, and without
   this correction the gap looks roughly twice the bar on a 48px heading.
   Width is measured by site.js and written to --bar-w: the bar spans the first
   word of the last line, or its first 5 characters if the word is longer, so it
   never runs across a space. The clamp is only a fallback if JS doesn't run.

   --bar-x is where that word starts, also measured by site.js. The bar is drawn
   from the first word, so it is drawn UNDER the first word — on every heading,
   whatever its text alignment. Centred headings used to get margin:auto here,
   which put the bar in the middle of the line while its width still came from
   the word at the start of it: the bar then underlined nothing in particular. */
.rule::after{
  --bar:6px;
  content:'';display:block;
  width:var(--bar-w, clamp(120px,26%,260px));
  height:var(--bar);
  margin-top:calc(var(--bar) - 0.19em);
  margin-left:var(--bar-x, 0px);
  background:var(--gold)}

/* Larger headings carry a proportionally heavier bar — and the gap follows it. */
.page-head .rule::after{--bar:8px}
.hero .rule::after{--bar:10px}

/* ---------- cta band ---------- */
.cta{background:var(--scarlet);color:#fff;padding:66px 0;text-align:center;
  border-top:5px solid var(--gold)}
.cta h2{margin-bottom:14px;color:#fff}
.cta .kicker{color:#fff}
.cta p{max-width:620px;margin:0 auto 28px;color:rgba(255,255,255,.94)}

/* ---------- prose: privacy, accessibility ----------
   A single measured column. Legal and policy text is read, not scanned, so the
   line length is deliberately shorter than the rest of the site. */

.prose{max-width:720px}
.prose h2{font-size:clamp(20px,2.3vw,26px);font-weight:900;margin:44px 0 14px;
  text-transform:uppercase;letter-spacing:.01em}
.prose h2:first-child{margin-top:0}
.prose p,.prose li,.prose dd{line-height:1.72}
.prose p{margin:0 0 16px}
.prose ul{margin:0 0 16px;padding-left:22px}
.prose li{margin-bottom:9px}
.prose dl{margin:0 0 16px}
.prose dt{font-weight:700;margin-top:16px}
.prose dd{margin:4px 0 0;padding-left:18px;border-left:3px solid var(--gold)}
.prose a{color:var(--scarlet);font-weight:700}
.prose a:hover{border-bottom:2px solid var(--gold)}
.prose .stamp{margin-top:44px;padding-top:20px;border-top:1px solid var(--line);
  font-size:14px;color:var(--mute)}

/* ---------- footer ---------- */
.foot{background:#0C0908;color:rgba(255,255,255,.72);padding:56px 0 0}
/* Even gaps between the four blocks, which a column grid cannot give you.
   The columns were 2fr 1fr 1fr 1fr, so the COLUMNS were evenly sized — but the
   text inside them is not. "What's On" is 74px in a 202px column and "Promoter
   pack" is 98px, so the space left over differed in each, and the gaps you
   could actually see came out at 105px, 168px and 166px.

   Laid out as a row instead, with each block only as wide as it needs and the
   leftover shared out equally between them. The gaps are then equal by
   construction and stay equal if a link is renamed. */
.foot-in{display:flex;flex-wrap:wrap;justify-content:space-between;
  gap:40px;padding-bottom:40px}
.foot-brand{flex:0 1 var(--brand-measure)}
.f-col{flex:0 0 auto}
/* The logo floats top-left and the blurb wraps round it, at 54px.

   It does NOT fill the height of the row, and that is a deliberate trade rather
   than an oversight. The row is 189px, set by the Explore list; this block comes
   to 140px, so about 50px is left over and the gold rule floats in the middle of
   it. Both ways of closing that gap cost more than the gap does:

     narrow the column until the text wraps further — the logo already takes
     70px off the width, so this ends at about 21 characters a line, and
     justified text at 21 characters is nothing but holes;

     grow the logo until it fills the height itself — needs 140px, which is
     far too big for a footer.

   So the measure stays at 340px, about 38 characters, which justifies cleanly,
   and the leftover height is simply leftover. If it ever wants closing, the
   lever is the Explore list rather than this block: tightening the footer link
   spacing would bring the row down to meet it, and shorten the whole footer at
   the same time. */
/* A column, so the block can fill the height the footer row gives it — which is
   set by the tallest thing in that row, the Explore list. The blurb sits at the
   top, the credit at the bottom, and the gold rule takes what is left.

   .foot-blurb keeps the logo and the blurb together as one flex item, so the
   two move as a unit and only the rule and the credit below take a share of the
   spare height. */
.foot-brand{display:flex;flex-direction:column}
/* flow-root so the float is contained — otherwise the logo, being taller than
   the text beside it, hangs out of the bottom and lands on the gold rule. */
.foot-blurb{display:flow-root}
.foot img{float:left;height:54px;width:auto;margin:3px 16px 2px 0}

/* margin:auto 0 is what centres it. An auto margin in a flex column swallows
   the free space, and one on each side swallows an equal share — so the rule
   sits exactly halfway between the blurb above and the credit below, whatever
   that distance turns out to be. It is the answer to "halfway between the two"
   that does not need a number, and it stays right if the blurb rewraps at a
   different window width.
   The minimum gaps are set on the neighbours rather than on the rule, because
   an auto margin cannot also carry a floor. 12 above and 10 below, keeping the
   2px difference that cancels the leading: the blurb ends with a few pixels of
   space below its last line and the credit begins with a few above its
   capitals, so equal numbers would leave the rule looking closer to the blurb.
   On a narrow screen, where there is no spare height to share out, those
   minimums are the whole gap. */
.foot-rule{display:block;flex:0 0 2px;background:var(--gold);
  width:100%;max-width:var(--brand-measure);margin:auto 0}
.foot-blurb{margin-bottom:12px}
/* One measure, shared by the blurb and the credit beneath it, and given in px
   rather than ch on purpose. A `ch` is the width of the digit zero in the
   element's OWN font-size, so the same `32ch` on a 14.5px paragraph and a 12px
   credit produced two different widths — 232px and 192px. The gold rule spans
   the credit, so it came out 40px shorter than the text it was dividing, and
   the credit line no longer fitted on one line either. */
.foot-brand{--brand-measure:340px}

/* Justified, to match the project's documents — both of them set their body
   paragraphs to justified and neither sets one to left.

   Hyphenation is switched on with it, and that is not optional at this measure.
   The column is about 36 characters, so a line holds six or seven words and
   there are only five or six gaps to absorb whatever space is left over. Take a
   long word down to the next line without hyphens and the remaining words on
   the line stretch far enough apart to leave a visible river of white running
   down the paragraph. Hyphenation breaks the word instead, so the leftover is
   small and the spacing stays even. It needs the lang attribute on <html> to
   know the rules; every page here carries lang="en-GB".

   The credit line underneath opts out — it is a single line, and the last line
   of justified text is never justified anyway, so it would only be a trap for
   the day somebody lengthens it. */
/* 15.5px, up from 14.5. The credit line beneath is sized by measurement to fill
   the gold rule and lands around 15.45px, so the blurb was the smaller of the
   two and the maker's credit was quietly the largest text in the footer. Both
   are 15.5 now — the credit is capped at that figure in sizeCredit(), so it can
   reach the rule but never overtake the band's own words. */
.foot-brand p{font-size:15.5px;max-width:var(--brand-measure);margin:0;
  text-align:justify;-webkit-hyphens:auto;hyphens:auto}

/* Left to itself a browser will break a word with two letters before the hyphen,
   which is how "future" came out as "fu-ture". These are the limits: only words
   of eight letters or more, and never fewer than four letters on either side of
   the break.

   In this paragraph that leaves exactly four words that could break at all —
   Creating, exciting, Kettering and Northampton — and of those only Northampton
   has a break that satisfies the four-either-side rule, at North-ampton. Every
   short word, "future" included, is now off limits entirely.

   -webkit- for Safari, which named these separately and earlier. Where neither
   is understood the browser falls back to its own loose defaults, so this is an
   improvement rather than a guarantee; if a bad break ever shows up somewhere
   unexpected, the certain fix is hyphens:manual and slightly looser word
   spacing. */
.foot-brand p{
  -webkit-hyphenate-limit-before:4;
  -webkit-hyphenate-limit-after:4;
  hyphenate-limit-chars:8 4 4}
.f-col{display:flex;flex-direction:column;gap:9px}
.f-col b{font-weight:700;font-size:11.5px;letter-spacing:.15em;text-transform:uppercase;
  color:var(--gold);margin-bottom:5px}
.f-col a{font-size:14.5px;text-decoration:none}
.f-col a:hover{color:var(--gold)}
/* The last line on the page, and it had 20px above and 20px below — the same
   spacing as any strip in the middle of a document, which left it sitting on the
   bottom edge of the window with nothing under it.

   More below than above, deliberately: a footer wants the page to end, not to
   stop. And when these two lines wrap onto separate rows on a narrow screen,
   row-gap keeps them apart instead of letting them close up into one block. */
/* Equal above and below. It was 22px above the small print and 40px beneath,
   which reads as the page having failed to finish — the eye measures the gap
   against the rule above it, and a bottom nearly twice the top looks like
   something was meant to be there. */
.foot-btm{display:flex;justify-content:space-between;gap:12px 18px;padding:22px 24px;
  border-top:1px solid rgba(255,255,255,.1);font-size:13px;flex-wrap:wrap}
.foot-btm a{text-decoration:none}
/* The maker's credit, in the brand column above the dividing rule rather than
   down in the small print with the charity number.

   Set apart rather than merely spaced. As a third paragraph in the same column
   it read as another sentence about the band, which it isn't — so it gets its
   own short gold rule above it and is stepped down in size and weight. The rule
   is the same device the headings use, at the width of a word rather than a
   heading, so it reads as house furniture rather than a new idea. */
/* The rule spans the column rather than being a 40px stub at the left of it.
   As a stub it read as a fragment — something that had been cut off, or the
   start of an underline that never finished. Full width it does the job it was
   there to do: it divides the band's description from the maker's credit, and
   the two read as two things rather than one paragraph with a mark above it.

   The column is set by .foot-brand p{max-width:32ch}, so the rule is given the
   same measure and lines up with the text it is dividing rather than with the
   grid column, which is wider. */
/* Equal air above and below, because it is a divider and a divider that sits
   closer to one of the two things it separates has picked a side. It was 26px
   above and 18px below.

   2px rather than 3px. The only other rule in this footer is the hairline over
   the copyright line; 3px of gold between a 14.5px text and a 12px one was
   shouting where it only needed to speak. */
/* .foot-brand p.credit, not .credit. `.foot-brand p` is a class plus an element
   and so outranks a bare class, whatever the order in the file — and this is a
   <p> inside .foot-brand. It was therefore silently taking font-size:14.5px and
   margin:0 from that rule and ignoring what is asked for here: the credit
   rendered at the same size as the blurb, too wide for its column so it wrapped
   to two lines, with NO gap above the gold rule at all. Only the colour and the
   letter-spacing were getting through, which is why it still looked different
   enough to seem deliberate.

   12 above and 10 below — a 24px divider, down from 46. The 16px reference it
   used to take from the logo gap has gone, because the logo no longer sits on a
   line of its own; the column's remaining rhythm is the 9px between the footer
   links, and 12 sits just above that.

   12 and 10, not 11 and 11. Equal numbers do not give equal gaps here: the
   paragraph above ends with roughly 3px of leading below its last line, and the
   credit below starts with roughly 5px above its capitals, so matched padding
   leaves the rule looking closer to the blurb than to the credit. The 2px
   difference cancels that out.

   No rule drawn here any more — .foot-rule is a real element between the two
   paragraphs, because only an element of its own can take an equal share of the
   leftover height above and below itself. A border or a pseudo-element is
   welded to one side or the other and can only ever sit at a fixed distance
   from it. */
/* Sized to reach the width of the gold rule above it, rather than stretched to
   it — justifying a single line was tried and looked like exactly what it was,
   a short line pulled apart.

   The 12px here is a floor, not the intended size. sizeCredit() in site.js
   measures the line and scales it up to meet the rule, the same way the header
   lockup is matched to its sub-line. It is done by measurement because it was
   twice done by arithmetic and was twice wrong: once leaving the line well
   short, once making it wide enough to wrap onto a second line.

   12px is what shows if that script never runs. It is under the size that fits
   in every case, so with scripts off the line is a little short of the rule and
   never wrapped, which is the right way round to fail. */
.foot-brand p.credit{margin:10px 0 0;
  max-width:var(--brand-measure);text-align:left;hyphens:manual;
  font-size:12px;letter-spacing:.06em;color:rgba(255,255,255,.55)}

/* ==========================================================================
   JUSTIFIED BODY TEXT
   ==========================================================================
   Applied to the running prose across the site, to match the project's
   documents, which set their body paragraphs justified.

   NOT applied to everything with words in it, and the line is drawn by
   measure. Justification works by stretching the spaces between words to fill
   the line: give it forty-five characters or more and there are enough gaps to
   absorb the slack invisibly, give it thirty and one long word wrapping leaves
   a hole you can see. So:

     justified          prose pages           100 characters
                        page ledes             90 or more
                        split columns          64 to 73
                        Book Us offers         53
                        biography panel        71

     left as they were  a spec answer          42
                        a news card blurb      36
                        a poster card's meta   40

   Hyphenation comes with it, on the same limits as the footer: eight-letter
   words minimum, four letters either side of the break. Without that a browser
   will break "future" as "fu-ture", which is how this was found in the footer.
   With it, the hyphen only ever lands somewhere a person would put it.

   The last line of a justified paragraph is never stretched, so ragged endings
   are correct and not a fault. */
.prose p, .prose li,
.lede,
.split p, .wall-intro p,
.offer p,
.bio-body p,
.spec-notes p,
.sec-head p:not(.kicker){
  text-align:justify;
  -webkit-hyphens:auto;hyphens:auto;
  -webkit-hyphenate-limit-before:4;
  -webkit-hyphenate-limit-after:4;
  hyphenate-limit-chars:8 4 4}

/* Anything that is a label, a caption or a note stays ranged left, whatever it
   sits inside — these are short and justification would only pull them apart. */
/* NOT a bare `figcaption`, which is what this said at first. There are two kinds
   on this site and they want opposite things. The captions under the Book Us
   collage are labels beneath a picture, and range left. The one on a quote is the
   attribution under a centred card, and belongs on the centre line with
   everything else in it.

   The bare selector caught both — and because justify aligns its LAST line to the
   start, and these are one line each, the speaker's name and their role both slid
   to the left edge of the block while the card around them stayed centred. It
   read as a centring bug rather than an alignment one, which is why it survived
   a look. Named by where they are now, so the two cannot be confused again. */
.prose .stamp, .hint, .ev-note, .card-date, .credit,
.photo-set figcaption, .cond, .spec dd{
  text-align:left;-webkit-hyphens:manual;hyphens:manual}

/* ---- the timeline arriving as you scroll ----
   Each entry rises as it reaches the viewport, a beat after the one above it,
   so a decade assembles itself rather than appearing whole. The same reveal
   machinery the rest of the site uses — data-rise-stagger on each decade's
   list — with one difference worth stating: the delay is capped further down
   the list than elsewhere, because a decade can hold five entries and a linear
   delay would leave the last arriving long after a reader has got to it.

   Movement is small and vertical only. A timeline is a vertical thing and
   anything sideways would fight the rail. */
.js-anim .tl[data-rise-stagger] > li{opacity:0;transform:translateY(14px);
  transition:opacity .5s ease, transform .5s cubic-bezier(.2,.7,.3,1)}
.js-anim .tl[data-rise-stagger].in > li{opacity:1;transform:none}

/* The square arrives after the words it belongs to, which reads as the entry
   being pinned to the rail rather than the two sliding in together. */
.js-anim .tl[data-rise-stagger] > li .ev::before{transform:translateX(-50%) scale(0);
  transition:transform .34s cubic-bezier(.2,.9,.3,1.4) .18s}
.js-anim .tl[data-rise-stagger].in > li .ev::before{transform:translateX(-50%) scale(1)}

@media(prefers-reduced-motion:reduce){
  .js-anim .tl[data-rise-stagger] > li,
  .js-anim .tl[data-rise-stagger] > li .ev::before{
    opacity:1;transform:none;transition:none}
  .js-anim .tl[data-rise-stagger] > li .ev::before{transform:translateX(-50%)}
}

/* ==========================================================================
   TOUCH
   ==========================================================================
   Everything here answers one of two questions a phone asks that a mouse never
   does.

   HOW BIG IS A FINGER?
   About 9mm across, which on a phone screen is roughly 44px. Anything smaller
   than that is a target you have to aim at, and aiming is what makes a site feel
   fiddly. Note that the target does not have to LOOK 44px — padding is invisible
   — so nothing below gets visually heavier, it just gets easier to hit.

   WHAT IF IT CANNOT HOVER?
   A finger has no hover state, so anything a mouse reveals by hovering is simply
   invisible on a phone. Every such thing needs either a touch equivalent or an
   honest admission that it is decoration and can go.

   Keyed on (hover:none) rather than a width, because both questions are about
   the thing doing the pointing, not the size of the screen it is pointing at. A
   tablet is wide and still has fingers. A small window on a laptop is narrow and
   still has a mouse.                                                          */
@media(hover:none){

  /* ---- the roster ----
     The cue that says a player can be opened slides up on hover, so on a phone
     it never appeared at all and twenty-nine portraits looked like twenty-nine
     photographs. It now sits where it lands, permanently, on every card that
     leads somewhere — which is also the only visible difference between a player
     with a biography and one without. */
  .player-cue{transform:translateY(0)}
  /* Hover underlines the name to reinforce the same message; with the cue always
     showing, the name would be permanently underlined for no reason. */
  .player-open:hover b{text-decoration:none}

  /* ---- targets ----
     The jump links are the worst of them: 12px type in 9px of padding is a 32px
     row, and there are eleven of them side by side. */
  .roster-jump a{min-height:44px;display:flex;align-items:center}
  .tl-toggle,.rt-clear,.txtlink,.nb-link,.reel-body .more{min-height:44px;
    display:inline-flex;align-items:center}
  /* The decade and section headings are already full-width rows; this only makes
     sure a short one is still a comfortable height. */
  .era-toggle,.sec-toggle{min-height:48px}
  /* The dots under the quotes are 9px of ink each. The ink stays at 9px — they
     are markers, and a bigger dot would read as a button — but each now sits in
     the middle of a 44px square that can actually be pressed. */
  .quote-dots{gap:0}
  .quote-dots button{width:44px;height:44px;background:none;
    display:grid;place-items:center}
  .quote-dots button::before{content:'';width:9px;height:9px;background:var(--line)}
  .quote-dots button[aria-current=true]::before{background:var(--ink)}
  .quote-dots button:hover{background:none}
  /* The record's filter checkbox: the input is 18px, the label beside it is the
     rest of the target, so the row is what has to be tall enough. */
  .rt-check{min-height:44px}
  .rec-table td,.rec-table th{padding-top:14px;padding-bottom:14px}

  /* ---- the biography panel's own scrollbar ----
     A 4px track is a mouse target, not a thumb one. It stays visible, because
     with the native bar hidden there would otherwise be nothing at all to say
     the biography carries on below the fold — but it widens to something that
     can actually be caught hold of, and moves further from the words so a
     scrolling finger does not land on it by accident.

     Dragging it is not the point. Scrolling the panel with a finger already
     works and always did; this is a signpost that happens to be draggable. */
  .bio-text .bio-bar{width:8px;right:8px}
  .bio-text .bio-thumb{left:-3px;right:-3px}

  /* ---- the highlight on a press ----
     Left alone, a tap flashes a translucent grey-blue box over the element —
     an Android default that belongs to no brand and least of all to this one.
     Scarlet at a tenth, so a press is acknowledged in the band's own colour. */
  a,button,[role=button],summary,label{-webkit-tap-highlight-color:rgba(190,29,46,.10)}

  /* Stops a double tap zooming instead of pressing, which on a page of small
     links is the difference between a site that responds and one that argues. */
  a,button,[role=button],input,select,textarea,summary{touch-action:manipulation}
}

/* Held at 100 so a phone turned sideways does not inflate the type to fill the
   wider screen — Safari does this by default, and it silently undoes every
   measurement on the page. */
html{-webkit-text-size-adjust:100%;text-size-adjust:100%}

/* ==========================================================================
   THE BOX OFFICE
   ==========================================================================
   Written for a phone first and widened afterwards, which is the opposite way
   round from the rest of this stylesheet — and deliberately. Somebody browsing
   the band's history is at a desk with a cup of tea. Somebody buying a ticket
   is on a phone, on a train, having seen a post about a concert, and will give
   up if it is fiddly. So the phone layout is the design and the desk is the
   variation.

   Everything below inherits the site's own type, colour and spacing. Nothing
   here is a second design system for a corner of the site; a ticket page that
   looks like a different website is a ticket page people abandon, because the
   moment a payment stops looking like the thing you clicked from is the moment
   you wonder whether it is real.                                             */

/* ---- choosing how many ---- */
.tk-row{display:flex;align-items:center;justify-content:space-between;gap:16px;
  padding:16px 0;border-bottom:1px solid var(--line)}
.tk-row:first-child{border-top:1px solid var(--line)}
.tk-row b{display:block;font-weight:700;font-size:16px}
.tk-row span{display:block;font-size:13.5px;color:var(--mute);margin-top:2px}

/* The stepper. The number field stays, and stays typeable, for anyone who would
   rather — but on a phone changing a 1 to a 2 by hand means summoning a
   keyboard to press one key, and these are 44px targets that do not. */
.tk-count{display:flex;align-items:center;gap:0;flex:0 0 auto}
.tk-step{width:44px;height:44px;padding:0;font:inherit;font-size:20px;
  line-height:1;background:var(--tint);color:var(--ink);
  border:1px solid var(--line);cursor:pointer;transition:.15s}
.tk-step:hover{background:var(--ink);border-color:var(--ink);color:#fff}
.tk-count input{width:56px;height:44px;text-align:center;font:inherit;
  font-weight:700;font-size:17px;border:1px solid var(--line);border-left:0;
  border-right:0;border-radius:0;background:#fff;color:var(--ink);
  -moz-appearance:textfield}
/* The browser's own up/down arrows are about 12px tall and sit on top of each
   other. They are worse than useless beside a 44px button that does the job. */
.tk-count input::-webkit-outer-spin-button,
.tk-count input::-webkit-inner-spin-button{-webkit-appearance:none;margin:0}
.tk-count input:focus{outline:none;border-color:var(--gold)}

/* ---- what it comes to ---- */
.tk-summary{background:var(--tint);border:1px solid var(--line);padding:24px 26px}
.tk-summary h3{font-size:14px;font-weight:900;letter-spacing:.16em;
  text-transform:uppercase;margin:0 0 14px}
.tk-lines{list-style:none;margin:0;padding:0}
.tk-lines li{display:flex;justify-content:space-between;gap:14px;
  padding:7px 0;font-size:15px}
.tk-total{display:flex;justify-content:space-between;align-items:baseline;
  margin:12px 0 0;padding-top:12px;border-top:2px solid var(--ink);
  font-weight:700}
.tk-total b{font-size:24px;font-weight:900}

.tk-left{display:inline-block;font-weight:700;font-size:12px;letter-spacing:.1em;
  text-transform:uppercase;color:var(--royal);margin:0 0 10px}
.tk-left.gone{color:var(--mute)}

/* ---- the clock on the checkout ----
   Prominent because it is the only thing on that page that is running out, and
   a hold that expires while somebody is looking for their card, with no warning
   they were on the clock, is the single most annoying thing a box office can
   do. */
.tk-clock{background:var(--ink);color:#fff;padding:20px 24px;margin-bottom:24px}
.tk-clock b{display:block;font-size:30px;font-weight:900;line-height:1;
  font-variant-numeric:tabular-nums}
.tk-clock span{display:block;font-size:13.5px;color:rgba(255,255,255,.72);
  margin-top:6px}
.tk-clock.soon{background:var(--scarlet)}
.tk-clock.gone{background:var(--mute)}

/* ---- test mode ----
   Loud on purpose. This appears only while there is no way to take a real
   payment, and the one thing that must never happen is somebody believing they
   have paid when nothing was taken. */
.tk-test{border:3px dashed var(--gold);background:#FFFBF0;padding:22px 24px}
.tk-test b{display:block;font-weight:900;font-size:15px;letter-spacing:.1em;
  text-transform:uppercase;color:var(--royal);margin-bottom:8px}

/* ---- the ticket ---- */
.tk-head{margin-bottom:26px}
.tk-head h1{font-size:clamp(26px,5vw,36px);line-height:1.1;margin:0 0 8px}
/* The heading that stands in while the tickets load. Sized like the real one so
   nothing jumps when it is replaced. */
.tk-loading{font-size:clamp(26px,5vw,36px);line-height:1.1;margin:0 0 8px;
  color:var(--mute)}
.tk-when{font-weight:700;font-size:17px;margin:0 0 2px}

.tk-pass{border:2px solid var(--ink);background:#fff;padding:22px;
  margin-bottom:20px;text-align:center}
.tk-qr{display:flex;justify-content:center;margin-bottom:14px}
.tk-qr svg{width:min(260px,70vw);height:auto;display:block}
.tk-pass-foot b{display:block;font-weight:900;font-size:13px;letter-spacing:.12em;
  text-transform:uppercase}
/* The typed fallback, deliberately big and spaced: it gets read off a screen in
   the dark by somebody who has already given up on the camera. */
.tk-short{display:block;font-weight:900;font-size:26px;letter-spacing:.22em;
  text-indent:.22em;margin:8px 0 4px;font-variant-numeric:tabular-nums}
.tk-used{display:block;font-weight:700;font-size:13px;color:var(--royal)}
.tk-pass.used{border-color:var(--line);background:var(--tint);opacity:.72}

.tk-terms{font-size:12.5px;color:var(--mute);margin-top:26px;
  padding-top:16px;border-top:1px solid var(--line)}
.tk-legal{font-size:11.5px;color:var(--mute)}

.tk-done h3{font-size:22px;margin:0 0 6px}

/* ---- the door scanner ----
   The verdict is enormous because it is read at arm's length, in the dark, by
   somebody with a queue in front of them. Colour alone never carries it: every
   state also says what it is in words, for anyone who cannot tell scarlet from
   green and for the far more common case of a phone screen washed out by a
   floodlight. */
.scan-verdict{padding:22px 24px;margin-bottom:18px;background:var(--tint);
  border:2px solid var(--line);text-align:center}
.scan-verdict b{display:block;font-size:clamp(26px,7vw,40px);font-weight:900;
  letter-spacing:.06em;line-height:1.1}
.scan-verdict span{display:block;font-size:14px;margin-top:6px}
.scan-verdict.admit{background:#0B6B3A;border-color:#0B6B3A;color:#fff}
.scan-verdict.again{background:var(--gold);border-color:var(--gold);color:var(--ink)}
.scan-verdict.unpaid,
.scan-verdict.unknown,
.scan-verdict.err{background:var(--scarlet);border-color:var(--scarlet);color:#fff}

.scan-cam{background:var(--ink);margin-bottom:18px;aspect-ratio:4/3;
  display:grid;place-items:center;overflow:hidden}
.scan-cam video{width:100%;height:100%;object-fit:cover;display:block}
.scan-cam .ev-note{color:rgba(255,255,255,.8);padding:20px}

.form-err{background:#FFF4F4;border-left:4px solid var(--scarlet);
  padding:14px 16px;margin:14px 0;font-size:15px;color:var(--ink)}

.wrap-narrow{max-width:620px}

/* ---- on a wider screen ---- */
@media(min-width:820px){
  .tk-summary{position:sticky;top:calc(var(--hdr-h) + 24px)}
}
@media(max-width:560px){
  /* The summary belongs above the form on a phone: it is what they came to
     check, and below the form it is under the fold behind a keyboard. */
  .tk-row{padding:14px 0}
  .tk-summary{padding:20px}
  .tk-pass{padding:18px 14px}
}

/* ==========================================================================
   THE ADMIN
   ==========================================================================
   Used by volunteers who did not ask to be webmasters, often on a phone, often
   months apart. So it is built round three things.

   NOTHING LOOKS TECHNICAL. It uses the site's own type and colour, so it feels
   like the website rather than like software. No monospace, no grey panels of
   settings, nothing labelled "record" or "field".

   THE LIST IS SCANNABLE AND THE FORMS ARE SHUT. Twenty-nine players all open at
   once is a page nobody can find anything in. Shut, it is a list you read.

   IT WORKS WITH A THUMB. Every row is a target, the save button is always
   reachable, and nothing depends on hovering.                                */

/* The admin's heading block now sits inside .page-head — the same ink banner
   What's On, Listen and History open with, which brings the crest watermark and
   the gold edge with it. This only lays the two halves out; everything that
   makes it look the way it does comes from that rule. */
.ad-head-in{display:flex;flex-wrap:wrap;align-items:flex-end;
  justify-content:space-between;gap:20px}
.ad-head-in h1{margin-bottom:6px}

/* The right-hand column of the banner: who you are, and the one action this
   screen has. Stacked, right-aligned, and level with the heading rather than
   under a rule at the foot of the band. */
/* THE TWO BLOCKS ARE ONE BLOCK. Right-aligned but self-sized, the account row
   and the save button were two different widths stacked at an angle to each
   other, which is what "unbalanced" looks like when you cannot name it: the
   column has no edge on the left, only a ragged one. Stretching both to the
   width of the wider of them gives the stack two straight sides, and the
   button — the thing this screen is FOR — becomes the largest object in the
   corner rather than a smaller shape hanging off the row above it. */
.ad-head-side{display:flex;flex-direction:column;align-items:stretch;gap:12px;
  width:max-content;margin-left:auto}
.ad-save{text-align:right}
.ad-head-side .ad-save .btn{width:100%}
.ad-save .hint{margin:8px 0 0;max-width:280px}

/* ---- whose account this is ----
   BESIDE THE HEADING, WITH THE SAVE BUTTON, on every screen but the front page.
   It was a row of its own across the foot of the banner with a rule above it,
   which put a line across a black band for no reason anybody could name and
   left the two things a person reaches for — who am I, and save — a hand's
   width apart. They are one column now, right-hand side, level with the words
   they belong to.

   THE ADDRESS IS SHOWN RATHER THAN HIDDEN BEHIND A HOVER. It is one line, it
   fits, and the account IS the address on this site — a card that appears on
   hover is a card nobody on a phone can open. */
.ad-you{display:flex;align-items:center;justify-content:flex-end;
  gap:12px;margin:0;text-align:left}
.ad-you-text{display:flex;flex-direction:column;min-width:0;gap:1px}
.ad-you-text b{font-weight:700;font-size:14px;line-height:1.25}
.ad-you-text span{font-size:12.5px;line-height:1.3;color:rgba(255,255,255,.72);
  overflow-wrap:anywhere}
/* Gold on ink, like every other accent on a dark surface here — 11.50:1, and
   11.50:1 the other way round when it fills on hover. */
.ad-you-out{font:inherit;font-weight:700;font-size:12.5px;letter-spacing:.09em;
  text-transform:uppercase;min-height:44px;padding:0 13px;cursor:pointer;
  background:none;border:1px solid rgba(255,255,255,.4);color:var(--gold);
  transition:.15s}
.ad-you-out:hover{background:var(--gold);border-color:var(--gold);color:var(--ink)}
.ad-you-out:focus-visible{outline:3px solid var(--gold);outline-offset:3px}

@media(max-width:820px){
  /* Flush left with the heading above it, once there is no right-hand column
     for it to line up under. */
  .ad-head-side{align-items:flex-start;width:100%}
  .ad-you{justify-content:flex-start}
}


/* ---- THE GOLD BAR DRAWS ITSELF HERE TOO ----
   The one animation this site is recognisable by: the gold rule under a heading
   grows from the left after the words have landed. Every public page does it as
   the section scrolls in; the admin did not do it at all, so moving from the
   site to the admin was a small change of world.

   The same movement and the same timing as the public pages — 0.75s on the same
   curve, after a 0.38s beat — copied deliberately rather than approximated, so
   the two halves look like one thing.

   AN ANIMATION RATHER THAN A TRANSITION, because the admin does not scroll its
   headings into view: it replaces them. A heading drawn into the page runs this
   once as it arrives, and the banner's heading — which is rewritten in place on
   every screen — is made to run it again by taking the class off and putting it
   back. scaleX, not width: a transform does not touch layout, so nothing round
   it reflows while it grows. */
.ad-rule-draw::after{animation:ad-rule-draw .75s cubic-bezier(.22,.61,.36,1) .38s both}
@keyframes ad-rule-draw{from{transform:scaleX(0)}}
.ad-rule-draw::after{transform-origin:left}

@media(prefers-reduced-motion:reduce){
  .ad-rule-draw::after{animation:none}
}

/* ---- moving between the admin's screens ----
   They are not pages — one element is emptied and refilled — so without this a
   press changes everything on screen in the same frame, which reads as a jolt
   rather than as having gone somewhere.

   Sideways, and the direction means something: deeper in from the right, back
   out from the left, the way every phone moves between a list and the thing on
   it. It matches how the front page is arranged, which is the one arrangement
   everybody can already read.

   .2s is short. This is on the path between somebody and the correction they
   came to make, possibly at ten to eight on a concert night, and a transition
   that has to be waited for is worse than none. Fading only the opacity would
   be safer still, but it says nothing about which way you went.

   Nothing on the way out — the old screen is gone the instant the new HTML is
   written, and keeping it to animate would mean holding two copies of a form
   in the page with the same ids in both.

   NAMED ad-slide-*, NOT ad-fwd/ad-back. .ad-back is already the "← ADMIN"
   button, and putting that class on #adminBody dressed the whole screen as one
   — small capitals, letter-spacing, and the button's own ← turning up in front
   of the page. Nothing in the file doing it looked wrong.

   SWITCHED OFF FOR REDUCED MOTION, NOT ON FOR NO-PREFERENCE. This was written
   the other way round — inside @media(prefers-reduced-motion:no-preference) —
   which is the only place in this file that asks the question that way, against
   thirteen that turn things off under `reduce`. It also fails in the wrong
   direction: anything that does not answer the question gets no animation at
   all, where the whole rest of the site would animate and then be told to stop.
   Written like everything else, it works unless somebody has asked it not to. */
/* ONE VOCABULARY, NOT FOUR EFFECTS. Everything that moves in the admin uses the
   same easing and one of two durations, so the whole thing reads as one piece
   of software rather than as four people's ideas. --ad-ease overshoots very
   slightly at the end, which is what stops a movement feeling mechanical.

   Depth is carried by scale and a little blur rather than by distance alone: a
   screen arriving comes from very slightly too small and slightly out of
   focus, the way something does when it is settling into place. Going back it
   arrives from slightly too large, as though stepping out of the thing just
   left. That is the difference between "the content changed" and "I went
   somewhere".

   THE BLUR IS 3px AND LASTS 0.2s. Blurring a whole screen is the most
   expensive thing here, and on a slow laptop an over-generous one turns a
   transition into a stutter. Three pixels is enough to read as focus pulling
   in and cheap enough not to be noticed as work. */
.ad-work{--ad-ease:cubic-bezier(.22,.9,.28,1.06);--ad-quick:.18s;--ad-calm:.26s}

/* IT GROWS FROM WHAT WAS PRESSED. transform-origin defaults to the middle of
   the element, and #adminBody is as tall as the page — so the pivot sat a long
   way down and the zoom looked like it came from the bottom left. admin.js
   measures the pressed tile and writes --from-x and --from-y here.

   The fallback is top centre, not the middle: with nothing to measure — the
   browser's Back button, a reload — a page should start from where its first
   line is, which is the top. */
#adminBody.ad-slide-fwd,#adminBody.ad-slide-back{
  transform-origin:var(--from-x,50%) var(--from-y,0px)}

/* Going in, the scale does the work: the screen opens out of the tile, and the
   sideways nudge that used to say "forward" would now fight the origin.
   Coming back there is nothing to grow from — you are returning to a page, not
   opening a thing — so that one keeps the drift from the left. */
#adminBody.ad-slide-fwd {animation:ad-slide-fwd  var(--ad-calm,.26s) var(--ad-ease) backwards}
#adminBody.ad-slide-back{animation:ad-slide-back var(--ad-calm,.26s) var(--ad-ease) backwards}
@keyframes ad-slide-fwd {
  from{opacity:0;transform:scale(.94);filter:blur(3px)}
}
@keyframes ad-slide-back{
  from{opacity:0;transform:translateX(-14px) scale(1.02);filter:blur(3px)}
}

/* Whatever stands above the tiles — the strip of figures and the jobs list on
   the front page, the back button and the sentence on a hub — moves with them
   rather than being there already. It was the fixed point everything else
   arrived around, which is what made the tiles feel late rather than staggered. */
.ad-status,.ad-todo,.ad-intro{
  animation:ad-pop var(--ad-calm,.26s) var(--ad-ease) backwards}

/* ---- the tiles arrive in the order they are read ----
   They used to appear in one frame, all nine at once, which is a lot of
   identical squares landing simultaneously. Forty-five milliseconds apart they
   assemble instead, top row before bottom — the stagger says the reading order
   out loud without anybody having to be told it.

   --in is written onto each tile by admin.js as it counts them out, because the
   number of tiles depends on what the person is ticked for. Nine fixed classes
   would be nine chances to be wrong. */
/* BACKWARDS, NOT BOTH — this one matters. A filled animation keeps its final
   value in force for the properties it animates, and it outranks ordinary
   declarations: with `both`, every tile would hold transform:none afterwards
   and .ad-tile:hover{transform:translateY(-3px)} would silently stop lifting.
   `backwards` applies the opening frame during the stagger delay, which is what
   keeps a tile invisible until its turn, and then gets out of the way. */
.ad-tile{animation:ad-pop var(--ad-calm,.26s) var(--ad-ease) backwards;
  animation-delay:var(--in,0ms)}
@keyframes ad-pop{
  from{opacity:0;transform:translateY(10px) scale(.965);filter:blur(2px)}
}

/* ---- a row opening ----
   Nothing had to change in the JavaScript for this: the fold sets and clears
   the hidden attribute, and :not([hidden]) matches the moment it is cleared.
   So the opening animates and the closing stays instant, which is the right
   way round — you watch something open, you do not watch it shut. */
.ad-entry .ad-body:not([hidden]){
  animation:ad-unfold var(--ad-quick,.18s) var(--ad-ease) backwards}
@keyframes ad-unfold{
  from{opacity:0;transform:translateY(-6px) scale(.995);filter:blur(2px)}
}

/* ---- the save says so ----
   A gold sweep straight across the button, once. The most important press in
   the admin used to change a word and move nothing. */
#adSave{position:relative;overflow:hidden}
#adSave.ad-swept::after{
  content:'';position:absolute;inset:0;pointer-events:none;
  background:linear-gradient(100deg,transparent 20%,var(--gold) 50%,transparent 80%);
  transform:translateX(-100%);
  animation:ad-sweep .6s var(--ad-ease) both}
@keyframes ad-sweep{ to{transform:translateX(100%)} }

/* And the sentence underneath arrives rather than appearing. */
.ad-note:not([hidden]){
  animation:ad-unfold var(--ad-quick,.18s) var(--ad-ease) backwards}

@media(prefers-reduced-motion:reduce){
  #adminBody.ad-slide-fwd,#adminBody.ad-slide-back,
  .ad-tile,.ad-status,.ad-todo,.ad-intro,
  .ad-entry .ad-body:not([hidden]),.ad-note:not([hidden]),
  #adSave.ad-swept::after{animation:none}
}

/* The sign-out tile. Same shape as its neighbours — it is a way out, not an
   alarm — but marked differently so it does not read as one more place to go.
   A different-coloured tile among navigation would look like a warning; a
   different MARK reads as "this one is not like the others".

   GOLD, NOT SCARLET, BECAUSE THE PLATE IS INK. The foot tiles carry
   .ad-tile.away, whose plate is ink. Scarlet on ink measures 3.07:1 — the bare
   floor for a graphic, and it looks like the floor: a dark red shape on a
   near-black square. Gold on ink is 11.50:1, and gold is the accent this site
   already uses on ink everywhere else — the kicker, the bar under every
   heading, the rule on the welcome.

   Scarlet leads on white. On ink it is gold. */
.ad-tile[data-key="signout"] .ad-plate{color:var(--gold)}

/* HOVER GOES SCARLET, LIKE ITS NEIGHBOURS, and the mark stays white.

   It inverted to a gold plate with an ink mark, which measures 11.50:1 and is
   perfectly legible — but it turned the mark black at the moment of pressing,
   which reads as the icon changing rather than the tile lighting up.

   Keeping the plate gold and making the mark white is not the fix: white on
   gold is 1.64:1, which is no mark at all. So the plate changes instead, to the
   same scarlet the other away tiles use, where white sits at 6.17:1.

   Gold at rest is what marks this tile out. The hover is only feedback, and
   feedback that matches everything else is one less thing to explain. */
.ad-tile[data-key="signout"]:hover .ad-plate,
.ad-tile[data-key="signout"]:focus-visible .ad-plate{
  background:var(--scarlet);color:#fff}

/* The tick on the sign-in box. .ad-tick already gives it a 44px row; this only
   places it in the form and keeps the wording beside it rather than under. */
.ad-stay{margin-top:18px}
.ad-stay + .hint{margin-top:2px}

/* On ink, the muted grey the hints use everywhere else is barely there. */
.page-head .hint{color:rgba(255,255,255,.7)}

/* The banner is flush with the header, and the work below it starts where a
   section normally would. */
.ad-work{padding-top:34px;padding-bottom:64px}

/* The save button follows you down the page. On a phone the sections are long
   and the button would otherwise be a scroll away from wherever you were
   typing — which is how somebody edits four things and saves none of them. */
@media(max-width:820px){
  .ad-top{display:block}
  .ad-save{position:sticky;bottom:0;z-index:20;text-align:left;
    background:#fff;border-top:2px solid var(--ink);
    margin:0 -24px;padding:12px 24px calc(12px + env(safe-area-inset-bottom));
    display:flex;align-items:center;gap:14px}
  .ad-save .btn{flex:0 0 auto}
  .ad-save .hint{margin:0;max-width:none;font-size:12.5px}
}

/* ---- the sections across the top ----
   A scrolling row rather than a stack, so the page does not open with a
   screenful of navigation before any content. */
/* The strip scrolls sideways when there is not room for nine. A tab sliced in
   half at the edge reads as a broken page; the same tab fading out reads as
   "there is more this way", which is what is true. */
.ad-tabs{display:flex;gap:6px;overflow-x:auto;padding-bottom:12px;
  margin-bottom:24px;border-bottom:2px solid var(--ink);
  scrollbar-width:none;
  -webkit-mask-image:linear-gradient(to right,#000 calc(100% - 34px),transparent);
  mask-image:linear-gradient(to right,#000 calc(100% - 34px),transparent)}
.ad-tabs::-webkit-scrollbar{display:none}
.ad-tab{flex:0 0 auto;font:inherit;font-weight:700;font-size:12.5px;
  letter-spacing:.09em;text-indent:.09em;text-transform:uppercase;
  min-height:44px;padding:0 16px;cursor:pointer;
  background:var(--tint);color:var(--ink);border:1px solid var(--line);
  transition:.15s}
.ad-tab:hover{background:var(--ink);border-color:var(--ink);color:#fff}
.ad-tab.on{background:var(--scarlet);border-color:var(--scarlet);color:#fff}

/* Home is the way back, not a tenth section, so it is drawn as one: a gold
   edge that reads as a marker rather than another equal choice, and it keeps
   that edge when it is the tab you are on. */
.ad-tab-home{border-left:4px solid var(--gold)}

.ad-intro{margin-bottom:26px}

/* The lede on a section page runs the width of the column, because everything
   under it does: the count, the find box, the add button and every row in the
   list all reach the right-hand edge. Held at 62ch it stopped a couple of
   hundred pixels short of all of them and read as a mistake rather than a
   measure — the eye takes the list's edge as the page's edge and the text
   looks broken off. At the widths this page is used at that is around 75
   characters, which is inside the limit prose pages are set at and well past
   the 45 justification needs. */
.ad-intro .lede{max-width:none;margin-top:14px}

/* ---- the tiles ----
   The first screen is two choices, so they are large: half the width each, and
   a plate big enough to be the thing you aim at rather than a decoration beside
   the words. Inside a choice the tiles are smaller but still substantial — nine
   across one row made each one narrow, small-marked and surrounded by white
   space, which is the arrangement the screenshot showed and the reason for
   this. Three across, three rows down, fills the same space with bigger things. */
/* --gap is declared rather than typed twice: the sign-out's offset below is
   worked out from the column width, and a gap changed in one place and not the
   other would put it a few pixels out — which is exactly the fault it is there
   to fix. */
.ad-home{--gap:14px;--pad:20px;
  display:grid;gap:var(--gap);grid-template-columns:repeat(auto-fit,minmax(190px,1fr))}
.ad-home-top{grid-template-columns:repeat(auto-fit,minmax(280px,1fr));gap:16px}
/* ONE THING TO DO IS DRAWN AS ONE THING. Somebody ticked only for ticketing had
   a half-width tile and a screen's worth of white beside it, which reads as a
   page that failed to finish loading rather than as a page with one job on it.
   Laid out along its own length instead: the mark at the left, the words beside
   it, the way the wide tiles at the foot already are. */
.ad-home-top.one{grid-template-columns:1fr}
.ad-home-top.one .ad-tile{flex-direction:row;align-items:center;text-align:left;
  flex-wrap:wrap;gap:6px 24px;padding:24px 26px}
/* .ad-tile.big is named in these because it is declared LATER in this file and
   would otherwise tie on specificity and win — the plate stayed 104px and the
   bar stayed 178px tall with sixty of them empty. */
.ad-home-top.one .ad-tile.big .ad-plate{width:76px;height:76px;margin:0}
.ad-home-top.one .ad-tile.big .ad-icon{width:38px;height:38px}
/* The name and the line under it sit side by side along the bar rather than
   stacked in the middle of it: stacked, the tile was 180px tall with 60 of them
   empty. */
.ad-home-top.one .ad-tile.big .ad-tile-name{font-size:21px}
.ad-home-top.one .ad-tile.big .ad-tile-sub{margin:0;font-size:14.5px;max-width:none}
/* THE THREE THAT ARE NOT EDITING, IN A ROW, with the way out on the row below.
   Stacked full-width they each centred their own contents, so the three marks
   sat at three different distances from the left — the eye reads that as
   crooked before it reads any of the words.

   auto-fit rather than a fixed three, because People is only there for somebody
   ticked for it. With two the row is two, evenly; with a fixed three it would
   be two and a gap.

   Where the way out goes is set further down, next to how it is drawn. */
.ad-home-foot{margin-top:16px;
  grid-template-columns:repeat(auto-fit,minmax(230px,1fr))}
@media(min-width:820px){
  /* Nine tiles want three rows of three, not one row of nine. auto-fit would
     give five and four, which reads as an accident. */
  .ad-home{grid-template-columns:repeat(3,1fr)}
  .ad-home-top{grid-template-columns:repeat(2,1fr)}
  /* .ad-home-foot is NOT pinned to one column here any more. It was, which
     quietly beat the rule above on every desktop screen — the only place
     anybody was looking at it. Its auto-fit stands. */
}

.ad-tile{display:flex;flex-direction:column;align-items:center;text-align:center;
  padding:30px 16px 26px;background:var(--tint);color:var(--ink);
  border:1px solid var(--line);font:inherit;cursor:pointer;text-decoration:none;
  transition:.15s}
.ad-tile:hover,.ad-tile:focus-visible{background:#fff;border-color:var(--ink);
  transform:translateY(-3px)}

/* The plate is the app icon: one flat shade, the mark knocked out of it in
   white, corners rounded enough to read as a tile without becoming a pill.
   Scarlet leads. */
/* SQUARE. Every corner on this site is square on purpose — the stylesheet
   writes border-radius:0 in a dozen places purely to overrule the browser's own
   ideas. The crest has no rounded corner in it, and neither should anything
   standing next to it. A rounded plate is the single detail that would have
   made the admin look like a different product bolted on. */
.ad-plate{display:grid;place-items:center;width:76px;height:76px;
  margin-bottom:18px;border-radius:0;background:var(--scarlet);color:#fff;
  transition:.15s}
.ad-icon{width:38px;height:38px;flex:0 0 auto}
.ad-tile:hover .ad-plate,.ad-tile:focus-visible .ad-plate{background:var(--royal)}

.ad-tile-name{font-weight:700;font-size:17px;line-height:1.25}
.ad-tile-sub{margin-top:7px;font-size:13px;line-height:1.4;color:var(--mute);
  max-width:26ch}

/* The two on the first screen. Bigger again, because there are only two of them
   and the screen is otherwise empty — a large target is easier to hit on a
   phone and easier to believe on a laptop. */
.ad-tile.big{padding:46px 24px 40px}
.ad-tile.big .ad-plate{width:104px;height:104px;border-radius:0;
  margin-bottom:24px}
.ad-tile.big .ad-icon{width:52px;height:52px}
.ad-tile.big .ad-tile-name{font-size:24px;letter-spacing:-.01em}
.ad-tile.big .ad-tile-sub{font-size:14.5px}

/* Unsaved work, said in gold where you would go looking for it rather than only
   in the line beside the save button. Ink on gold, because white on gold is not
   readable and never has been. */
.ad-tile.unsaved .ad-plate{background:var(--gold);color:var(--ink)}
.ad-tile.unsaved .ad-tile-sub{color:var(--scarlet);font-weight:700}

/* Things that are not a list you change and save: the scanner, the box office,
   the live site. The plate says so before the words do. */
.ad-tile.away .ad-plate{background:var(--ink)}
.ad-tile.away:hover .ad-plate{background:var(--scarlet)}

/* The live site is not something you administer, so it goes underneath and lies
   down rather than standing up beside the two that are. */
/* Left, not centred. Centred, every tile put its mark wherever its own words
   happened to end, so no two lined up. */
.ad-tile.wide{flex-direction:row;justify-content:flex-start;gap:18px;
  padding:18px 20px;text-align:left}
.ad-tile.wide .ad-plate{width:52px;height:52px;border-radius:0;margin:0}
.ad-tile.wide .ad-icon{width:26px;height:26px}
.ad-tile.wide .ad-tile-name{font-size:15px}
.ad-tile.wide .ad-tile-sub{margin:2px 0 0;font-size:13px}

/* THE FOOT ROW IS A SMALL GRID, NOT A ROW OF THREE THINGS.

   As a flex row the mark, the name and the description were three siblings
   competing for one line, and in a third of the width the name lost: "What
   changed" and "View the site" each broke across two lines while the
   description sat beside them, so the tile had two ragged columns of text and
   no obvious reading order.

   Two columns instead — the mark, then the words — with the name above its
   description in the second. The mark spans both rows so it stays centred
   against the pair however tall they are. Nothing has to fit on one line, so
   nothing breaks in an odd place.

   Written after .ad-tile.wide rather than before it: both selectors are two
   classes, so specificity ties and source order is what decides. */
.ad-home-foot .ad-tile{display:grid;grid-template-columns:auto minmax(0,1fr);
  column-gap:16px;row-gap:1px;align-items:center;justify-content:start;
  text-align:left;padding:16px 20px}
.ad-home-foot .ad-plate{grid-row:1/3;align-self:center}
.ad-home-foot .ad-tile-name{grid-column:2;align-self:end;margin:0}
.ad-home-foot .ad-tile-sub{grid-column:2;align-self:start;margin:0;max-width:none}

/* THE BAR IS FULL WIDTH, THE CONTENTS LINE UP WITH THE MIDDLE COLUMN. Those are
   separate decisions, and it took getting each of them wrong on its own to see
   that.

   Full width says this is not a fourth place to go — it is the line under the
   three. But merely centring the contents inside it put the mark at a position
   nothing else on the page shares, a few pixels off the one above it, which
   reads as a near-miss rather than as a choice.

   So the contents are pushed to where the middle tile's contents start: one
   column, plus the gap, plus the padding every tile has. The mark then sits
   directly under the mark on What changed.

   THE OFFSET ASSUMES THREE ACROSS, so it is only applied at a width where the
   row really is three — 820px, where 3 x 230 + 2 gaps fits with room to spare.
   Narrower than that the row is two columns or one, and an offset of a third of
   the width would push the mark into the middle of nothing. There it simply
   starts at the left like every other tile.

   The one case it still gets wrong: an account with no people tick sees two
   tiles up there, and this lands to the right of the second. The arithmetic
   cannot know — the row is auto-fit, so how many columns there are is settled
   by the browser long after this stylesheet has had its say. */
.ad-home-foot .ad-tile[data-key="signout"]{grid-column:1/-1}

@media(min-width:820px){
  .ad-home-foot .ad-tile[data-key="signout"]{
    padding-left:calc((100% - 2 * var(--gap)) / 3 + var(--gap) + var(--pad))}
}

/* Nothing between the back link and the tiles since the lede went, so the gap
   under it is the gap it was holding open for two lines of type that are no
   longer there. */
.ad-intro-hub{margin-bottom:6px}

/* TEN THINGS IN THREES LEFT ONE ON ITS OWN, with two tiles' worth of nothing
   beside it at the bottom of the page — the hole that made this screen read as
   empty however much was on it. Nine of them are lists somebody edits; the
   tenth only reports. So the nine make a square, and the odd one out runs the
   width underneath as a bar, which is both a tidier page and a truer one. */
.ad-home .ad-tile-span{grid-column:1/-1}
.ad-intro-hub .lede{max-width:56ch}

.ad-back{display:inline-flex;align-items:center;gap:7px;margin-bottom:14px;
  min-height:44px;padding:0 2px;background:none;border:0;cursor:pointer;
  font:inherit;font-weight:700;font-size:12.5px;letter-spacing:.09em;
  text-transform:uppercase;color:var(--mute)}
.ad-back::before{content:'←';font-size:15px}
.ad-back:hover{color:var(--scarlet)}

@media(hover:none){
  /* Nothing lifts on a touch screen — the pointer that would have lifted it is
     a finger already covering it. */
  .ad-tile:hover{transform:none}
  .ad-tile:hover .ad-plate{background:var(--scarlet)}
  .ad-tile.away:hover .ad-plate{background:var(--ink)}
}

/* ---- the list ---- */
/* ---- the bar above a list ----
   How many there are, a box to find one in, and a way to add without scrolling
   to the foot of forty-four of them. */
/* ---- the strip across the top of the admin's front page ----
   What a person opening this actually wants to know before choosing anything:
   when it was last touched, what is coming, and whether anything needs doing.
   Without it the front page is a menu; with it, it is a desk. */
/* A RAIL, NOT FURNITURE. It was three tinted cells in a bordered grid with a
   second bordered bar beneath them, and together they took a hundred and fifty
   pixels above the two things this page is for — drawn heavily enough to be
   read first, when all four are things you glance at on the way past.

   Now they are four facts on one line: label, answer, hairline, next. The only
   border left is the one under the whole thing, which separates the rail from
   the choices instead of drawing a box round every fact in it. Nothing is
   tinted, because nothing here is a surface — it is type on the page. */
/* ---- the rail is set on a line, like anything else that is typeset --------
   Every line in it — each fact, the label over the jobs, a fact that has
   wrapped — sits 26px below the one before it, and nothing in it is allowed to
   grow its own line: the faces are pulled in at the margins so a row of squares
   takes the same height as a row of words. Breaks between the parts are half a
   line, which is the only measurement here that is not 26 or a multiple of it.

   That is what stops the stacked rail reading as three unrelated rows with
   different amounts of air around them, which is what it did while each row
   was as tall as whatever happened to be in it: 55px, then 32, then 31. */
.ad-rail{--rail-line:26px;
  padding:0 0 13px;margin:0 0 26px;border-bottom:1px solid var(--line)}

/* THE THREE FACTS ARE SPREAD ACROSS THE PAGE, not bunched at the left of it.
   Set as a row they took the width of their own words and left a third of the
   line empty, which reads as a row that ran out rather than one that was laid
   out. Three equal columns put each answer at a third of the way along and the
   dividers on the thirds, so the line is as wide as everything under it. */
/* THE AIR IS SHARED, NOT ALLOTTED. Equal columns gave each fact a third of the
   line whether it needed it or not, and the short answers left holes; putting
   the outer two on the page's edges and the middle one in the middle only moved
   the holes about — a hand's width after ONLINE and a mile before SAVED.

   The facts take the width of their own words and the room left over is split
   equally between them. Three gaps of the same size, both ends on the margins
   the page is set to, and it stays true as the words change: a longer concert
   title takes its space out of the gaps rather than out of the next fact. */
.ad-status{display:flex;flex-wrap:wrap;align-items:center;
  justify-content:space-between;gap:4px 28px;padding:0;margin:0}
/* THE LABEL SITS ON THE ANSWER'S OWN LINE. Centred, a 11.5px capital and a
   15px word are two boxes of different heights lined up through their middles,
   which puts the small capitals a pixel or so below where the eye expects them
   — SAVED sat low against "Never". Baselines are what the eye actually reads a
   line by, so that is what they are lined up on. */
.ad-status div{display:flex;align-items:baseline;gap:8px;
  min-height:var(--rail-line);padding:0;background:none;min-width:0}
/* THE MIDDLE FACT HAS FACES IN IT, and they were setting its baseline — a
   flex row takes its baseline from its first item, and its first item is a
   square with a letter in the middle. So ONLINE sat six pixels below NEXT and
   SAVED on the same line. The faces are drawn as type instead: an inline box
   on the line rather than a flex item in front of it, dropped so its middle
   sits on the middle of the lower-case, and pulled in at top and bottom so it
   cannot make its own line any taller than a line of words. The sentence after
   it is then what the whole fact is aligned by, like the other two.

   (The cell's answer also has to stop hiding its overflow, or the browser
   stops looking for a baseline in it at all and uses the bottom edge.) */
.ad-status #adHere{overflow:visible}
.ad-status div > b{flex:0 0 auto}

/* The two states, and the frame in between where the row is asked how wide it
   would rather be. Nothing is painted while it is measuring: it is set, read
   and unset without the browser drawing anything in between. */
.ad-status.is-measuring{flex-wrap:nowrap}
.ad-status.is-measuring div{flex:0 0 auto;min-width:auto}
.ad-status.is-measuring span,
.ad-status.is-measuring em{overflow:visible;text-overflow:clip}
/* Stacked, the three labels are three different lengths, so three answers
   started in three different places down the left of the page. Two columns
   instead — the labels in one, as wide as the longest of them, and every
   answer beginning on the same line as the others. */
/* No gap between the rows, because the line is the gap: every line of type in
   here is 26px below the last whether it is the next fact or the second line
   of the one above. */
.ad-status.is-stacked{display:grid;grid-template-columns:max-content 1fr;
  align-items:baseline;gap:0 10px}
.ad-status.is-stacked > div{display:contents}
/* And once they are stacked there is no reason left to cut anything: the line
   is no longer holding three facts, so a long answer takes a second line of
   its own rather than an ellipsis. Cutting is for the one-line state, where
   the alternative is a rail that is not a rail. */
.ad-status.is-stacked span,
.ad-status.is-stacked .ad-here em{white-space:normal;overflow:visible;
  text-overflow:clip}

/* AND WHEN THE WORDS ARE TOO LONG FOR THE LINE, the answer is cut rather than
   the line broken. "National Brass Band Championships of Great Britain" is a
   real concert title and there is nothing to stop a longer one; a rail that
   becomes three lines because of it is no longer a rail. Whatever is cut is
   still there in full on the title of the element, and every one of these
   facts is one press away from the page that says it properly. */
.ad-status div > span{min-width:0;overflow:hidden;text-overflow:ellipsis;
  white-space:nowrap}
.ad-status .ad-here{min-width:0;overflow:visible}
.ad-status .ad-here em{min-width:0;overflow:hidden;text-overflow:ellipsis;
  white-space:nowrap}
/* NO DIVIDERS. They were hairlines on the thirds, which was where the columns
   divided and not where the words did — with the facts set to the edges they
   pointed at nothing. Three labels in small capitals separate three answers
   perfectly well on their own. */
.ad-status b{display:inline;font-size:11.5px;font-weight:900;letter-spacing:.14em;
  text-transform:uppercase;color:var(--mute);margin:0;white-space:nowrap;
  line-height:var(--rail-line)}
.ad-status span{display:inline;font-size:15px;line-height:var(--rail-line);
  color:var(--ink)}
.ad-status em{font-style:normal;color:var(--mute)}

/* Things worth doing, each one a way straight to the place it is done. Listed
   only when there is something in them — an empty "nothing needs attention"
   panel is a panel that has to be read to learn it says nothing. */
/* ---- what wants doing ----
   One list, and everything feeds into it: work somebody started and did not
   finish, and information old enough to be worth looking at again. Both are a
   minute of somebody's time and a press away from where the minute is spent.

   BEHIND ONE LINE, CLOSED TO BEGIN WITH. Six chips across the top of the front
   page is a hedge in front of the door: every one of them is worth knowing and
   none of them is worth reading before somebody has decided what they came to
   do. The count is the nag; the list is the answer to it. */
/* THE COUNT RIDES ON THE END OF THE RAIL. It had a plate and a gold edge of
   its own, on a line of its own, under a grid of boxes — three separate ways of
   saying "look here" stacked on top of each other in front of the door. It is a
   line of type among the other three now, pushed to the far end, and the only
   one of them anybody can press, which the scarlet says on its own. */
/* THE JOBS THEMSELVES, ON THE LINE UNDER THE FACTS. The label reads as one of
   the rail's other labels, because that is what it is: NEXT, ONLINE, SAVED,
   WANTS DOING. What follows it is the work rather than a count of the work. */
.ad-jobs{display:flex;align-items:center;gap:12px;
  margin-top:calc(var(--rail-line) / 2)}
.ad-jobs > b{flex:0 0 auto;font-size:11.5px;font-weight:900;letter-spacing:.14em;
  text-transform:uppercase;color:var(--mute);white-space:nowrap;
  line-height:var(--rail-line)}
/* The jobs share the room left over, so the row ends where the page ends. */
.ad-jobs .ad-todo{flex:1 1 auto;margin:0;gap:7px}
/* They stretch to fill the line, but never squeeze: min-width:max-content
   means a job is either on the row at its full length or not on it at all.
   Without it the four that fit became four that fitted badly — "The committee
   and staff has nev…" — and a job you cannot read is not on the page in any
   sense that matters. */
.ad-jobs .ad-todo > li{flex:1 1 auto;min-width:max-content}
.ad-jobs .ad-todo > li > button{flex:1 1 auto}
.ad-jobs .ad-todo .ad-still{flex:0 0 auto}
.ad-jobs .ad-todo-rest{flex:0 0 auto}
/* NO PLATE ON THIS ONE. It is drawn inside the row of jobs, so it was picking
   up the job's own white box and gold edge and reading as a fifth job called
   "+2 more". It is the way to the rest of them, which is a different kind of
   thing and is said in the pressable capitals the rest of the admin uses. */
.ad-todo .ad-jobs-rest{display:inline-flex;align-items:center;min-height:34px;
  padding:0 4px;background:none;border:0;font:inherit;font-weight:700;font-size:12.5px;
  letter-spacing:.09em;text-transform:uppercase;color:var(--scarlet);
  cursor:pointer;white-space:nowrap;transition:.15s}
.ad-jobs-rest:hover{color:var(--royal)}
.ad-jobs-rest:focus-visible{outline:3px solid var(--gold);outline-offset:3px}
/* ON A PHONE IT IS A SENTENCE, NOT A ROW. Laid out as a row of parts it broke
   into three columns of two words each with the figure stranded on the left,
   which is what a flex row does to a sentence when there is no room for it.
   Set as ordinary running text it simply wraps, the way the words were written
   to. The facts above it lose their dividers at the same width, because a
   hairline between two lines that are already on separate lines is a rule
   pointing at nothing. */
/* ON A PHONE THERE ARE NO COLUMNS AND NO ROW. A third of a phone is not wide
   enough to say "Sun 6 Sep, in 9 days" in, and a line of jobs across it holds
   one job and a figure — so the facts stack a line each, and the jobs wrap as
   a small block with the label above them rather than beside them. */
@media(max-width:640px){
  .ad-rail{padding-bottom:13px;margin-bottom:20px}
  .ad-jobs{display:block}
  .ad-jobs > b{display:block}
  .ad-jobs .ad-todo > li{flex:0 1 auto}
}

#adJobs .ad-todo{animation:ad-unfold var(--ad-quick,.18s) var(--ad-ease,ease) backwards}

.ad-todo{margin:0 0 22px;padding:0;list-style:none;display:flex;flex-wrap:wrap;gap:8px}
.ad-todo li{display:flex;align-items:stretch}
.ad-todo button{display:inline-flex;align-items:center;gap:7px;min-height:34px;
  padding:0 11px;background:#fff;border:1px solid var(--line);
  border-left:3px solid var(--gold);font:inherit;font-size:13px;
  color:var(--ink);cursor:pointer;transition:.15s;text-align:left;
  white-space:nowrap}
.ad-todo button:hover{border-color:var(--ink);border-left-color:var(--scarlet)}
.ad-todo b{font-weight:900}

/* A reminder carries its own answer. Joined to the row it belongs to rather
   than floating beside it — the gold edge marks the start of one item, and two
   separate chips would read as two items. */
.ad-todo-check button:first-child{border-right:0}
.ad-still{border-left:1px solid var(--line) !important;
  font-weight:700;color:var(--royal);white-space:nowrap}
.ad-still:hover{background:var(--royal);border-color:var(--royal) !important;
  color:#fff}
.ad-still[disabled]{opacity:.6;cursor:default}

/* ---- who is online ----
   Faces first, names after them. Five at most: the sixth is a crowd, and the
   band has thirteen accounts.

   EVERY ONE OF THESE IS SCOPED TO .ad-status, and that is not decoration. The
   figure cells carry `.ad-status span{display:block}` — one class and one
   element, which beats a bare class — so `.ad-here{display:flex}` and
   `.ad-who{display:grid}` both lost to it: the faces and the names stacked
   instead of sitting on one line, and the initials sat in the top-left corner
   of their square rather than the middle of it. Measured, not guessed: a 40px
   box reporting display:block with the letter at the top of it. */
/* Set as type on the line rather than as a row of boxes beside it — see the
   note above the .ad-here-faces rule for why. Nothing here has a height of its
   own: the line the fact is on decides it. */
.ad-status .ad-here{display:inline-block;min-height:0;margin:0}
/* The count at the end of the row: the same square as a face, in the same ink
   as the initials, so it reads as one more of them rather than as a badge. */
.ad-status .ad-here-more{display:inline-flex;align-items:center;
  justify-content:center;min-width:26px;height:24px;padding:0 5px;
  font-weight:900;font-size:11.5px;letter-spacing:.02em;color:var(--mute);
  background:var(--tint);border:1px solid var(--line)}

/* A QUARTER OF AN INCH OF SQUARE, ON THE LINE. At forty pixels a face was
   taller than the line it sat on and made the fact half again as tall as the
   two either side of it — which is what made the stacked rail read as three
   rows with different amounts of air. Twenty-four fits inside a 26px line, and
   the negative margins mean even that is not counted against the line's
   height. */
.ad-status .ad-here-faces{display:inline-flex;align-items:center;
  vertical-align:-6px;margin:-6px 8px -6px 0}
.ad-status .ad-here .ad-who{display:grid;place-items:center;
  width:24px;height:24px}
/* AND THE INITIALS ARE NOT A LABEL. `.ad-status b` is the little grey capital
   heading over each figure — one class and one element again — so the letter
   inside a face came out at 10.5px, letter-spaced, and the colour of a caption.
   Everything that rule sets is set back here. */
.ad-status .ad-here .ad-who b{display:block;margin:0;font-size:11.5px;
  font-weight:900;letter-spacing:.03em;line-height:1;text-transform:none;
  color:var(--royal)}
/* SIDE BY SIDE, NOT OVERLAPPING. Overlapped by a third they looked like a row
   of people standing together — until you remember that most of these are
   initials rather than photographs, and a third of a letter is not a letter:
   "SB" and "D" beside each other came out as "SB|D" with the S half eaten.
   Photographs would have survived it; the thing this actually shows would not,
   and it is the state most accounts will be in for a while. */
.ad-status .ad-here-faces{gap:4px}
.ad-status .ad-here-one{display:flex}
.ad-status .ad-here em{display:inline;font-style:normal;color:var(--mute);
  font-size:13.5px;line-height:var(--rail-line)}

/* =============================================================================
   THE CARD
   =============================================================================
   Editing used to unfold underneath the row you pressed. In a list of
   thirty-two players that meant the thing you opened pushed everything below it
   off the screen, eleven fields ran down one column, and you could never see
   the list and the thing at once without scrolling past whichever you were not
   reading.

   It opens as a card over the page instead: one thing on the screen at a time,
   the page behind dimmed and still, Escape and a close button both shutting it.
   The browser's own <dialog> does the work — the keyboard stays inside it, and
   it draws above everything whatever it sits inside.
   ========================================================================== */
.ad-card{width:min(880px,calc(100vw - 32px));max-height:calc(100dvh - 48px);
  /* The dialog itself does not scroll — the column inside it does, and one bar
     is the whole point. A dialog scrolls by default, so this has to say so. */
  overflow:hidden;
  padding:0;border:0;background:#fff;color:var(--ink);
  box-shadow:0 24px 60px rgba(20,16,15,.28)}
.ad-card::backdrop{background:rgba(20,16,15,.55)}

/* THE PAGE BEHIND IS BLURRED, NOT ONLY DARKENED. Three pixels: enough to say
   "this is not what you are working on now", cheap enough not to stutter on a
   laptop. The same amount the admin's own screen changes use. */
.ad-card[open]{animation:ad-card-in var(--ad-calm,.26s) var(--ad-ease,ease) both}
.ad-card[open]::backdrop{animation:ad-card-dim var(--ad-calm,.26s) ease both;
  backdrop-filter:blur(3px)}
@keyframes ad-card-in{
  from{opacity:0;transform:translateY(14px) scale(.965);filter:blur(3px)}
}
@keyframes ad-card-dim{ from{opacity:0} }

/* ---- ONE SCROLL BAR, NOT TWO ----------------------------------------------
   The card was a column with a scrolling middle: a bar down the fields, inside
   the card, inside a page with a bar of its own. Two bars in the same corner is
   a thing to aim at wrongly, and it never says which one moves what.

   The card scrolls as one now, and the head and the foot stay put on top of it
   — the same two things staying still, by a means that does not invent a second
   bar to do it. */
.ad-card-in{display:block;max-height:calc(100dvh - 48px);overflow:auto;
  overscroll-behavior:contain}

/* The name of the thing, and what kind of thing it is. Ink, so the card has a
   head that holds it together and a reader knows at a glance what they opened —
   the list behind is white and the fields are white. */
.ad-card-top{display:flex;align-items:flex-start;justify-content:space-between;
  gap:18px;padding:20px 24px;background:var(--ink);color:#fff;
  position:sticky;top:0;z-index:3}


.ad-card-what{margin:0 0 3px;font-size:11.5px;font-weight:900;letter-spacing:.14em;
  text-transform:uppercase;color:var(--gold)}
.ad-card-name{margin:0;font-size:22px;line-height:1.15;font-weight:900;
  text-transform:none;letter-spacing:0}
.ad-card-x{flex:none;width:44px;height:44px;margin:-6px -8px 0 0;font:inherit;
  font-size:26px;line-height:1;background:none;border:0;color:#fff;
  cursor:pointer;transition:.15s}
.ad-card-x:hover{color:var(--gold)}
.ad-card-x:focus-visible{outline:3px solid var(--gold);outline-offset:2px}

/* ---- the fields ----
   TWELVE COLUMNS, AND A FIELD TAKES WHAT IT NEEDS. A date is three of them, a
   biography is all twelve. Every field used to be the full width, which made a
   form of eleven fields a column half a screen long and told the reader nothing
   about what was expected in any of them. */
.ad-card-fields{display:grid;grid-template-columns:repeat(12,1fr);
  gap:16px 20px;padding:20px 24px 24px}
/* THE CONTENTS SIT AT THE TOP OF THEIR CELL, NOT SPREAD DOWN IT. A grid item
   is as tall as the tallest thing in its row, and a grid inside one stretches
   its own rows to fill whatever height it is given — so beside a field with
   three lines of hint under it, the date's label was drawn 70px tall and its
   box 98, with the gap between them doing the stretching. Measured: a 176px
   cell holding 40px of label and 46px of input.

   align-content on the field, align-items on the row: the first stops a field
   spreading its own contents, the second stops a short field being stretched in
   the first place. */
.ad-card-fields{align-items:start}
.ad-card-fields .ad-field{align-content:start}
.ad-card-fields .f-sm{grid-column:span 3}
.ad-card-fields .f-md{grid-column:span 6}
.ad-card-fields .f-lg{grid-column:span 12}
.ad-card-fields .ad-sub{grid-column:1/-1;margin:10px 0 -6px}
/* Inside a card the boxes are a shade tighter than on a page of their own —
   16px type still, because anything smaller makes a phone zoom in on focus, but
   less air around it. */
.ad-card-fields .ad-field input,
.ad-card-fields .ad-field select,
.ad-card-fields .ad-field textarea{padding:10px 12px}
.ad-card-fields .ad-field textarea{min-height:120px}
.ad-card-fields .hint{margin:5px 0 0;font-size:12.5px;line-height:1.45}

@media(max-width:720px){
  /* One column on a phone, where twelve of anything is a fiction. */
  .ad-card{width:100vw;max-width:100vw;max-height:100dvh;margin:0}
  .ad-card-in{max-height:100dvh}
  .ad-card-fields{gap:16px;padding:18px}
  .ad-card-fields .f-sm,.ad-card-fields .f-md{grid-column:1/-1}
}

/* ---- being asked, rather than handed a form ----
   One question at a time, in the words somebody would use out loud. The
   question is the card's heading — big, on the ink, where the name of the thing
   sits when you are editing one — and the box under it is the only thing on the
   screen. */
/* THE QUESTION IS A HEADING, SO IT IS SET IN CAPITALS, like every heading on
   this site. The entry's own name on an edit card is not: on What's On a
   concert's title is a card heading and is set as somebody typed it, and this
   is the same words in the same role. Banner headings are capitals; names are
   not. */
.ad-card-ask .ad-card-name{font-size:clamp(25px,3.2vw,34px);max-width:36ch;
  text-transform:uppercase;letter-spacing:.005em;line-height:1.04;
  /* A HEADING BREAKS INTO EVEN LINES, not into a line and one leftover word.
     "Is it a concert or a contest?" was breaking after "a", which leaves the
     word hanging and reads as a mistake rather than as a heading. */
  text-wrap:balance}

/* ---- the crest behind the questions ----
   THE WHITE OF THE CARD, NOT THE INK ABOVE IT. The walkthrough asks one thing
   at a time, so the body of the card is mostly empty — which is the place on
   this site where the crest belongs: bottom-left, bleeding off the edge, one
   flat shade, the same file every white section of the site uses. The boxes
   and the words sit over it, as they do on the page behind. */
.ad-card-ask .ad-card-fields{
  /* THE TOP OF THE CROWN SETS THE SIZE. The crest is drawn as tall as the
     surface it is on and anchored to the bottom of it, so the point of the
     crown lands on the top edge — which is what `auto 100%` from the bottom
     means, and what every .mark on this site does. Bigger than that and the
     crown is cut off above the edge, which is the one part of the crest
     anybody would notice missing. */
  background:url('../img/gus-crest-light.png') left bottom/auto 100% no-repeat}
/* ---- one question is allowed the whole card ----
   A single box in the corner of an 880px card looks like a form that has failed
   to load the rest of itself. A question asked on its own is drawn at the size
   of the thing being asked. */
.ad-ask-one{padding:26px 24px 22px;min-height:150px;align-content:start}
.ad-ask-one .ad-field{grid-column:1/-1}

/* ONE QUESTION, AND THE CARD IS THE SIZE OF A QUESTION. A single line and a
   sentence of help left the card two hundred pixels deep between a diary behind
   it and a calendar step four hundred deep — the walkthrough grew and shrank
   from question to question, and the short ones looked like an afterthought.
   A floor under the body of the card: the answer box takes what it needs, and
   what is left is the crest rather than blank white. */
.ad-card-ask .ad-card-fields{min-height:clamp(210px,32vh,330px);align-content:start}

/* A line of type big enough to read across a room — this is the only thing on
   the screen, and somebody is looking at it while they think. */
/* ONE SIZE, READ BY BOTH THE BOX AND THE GREY WORDS BEHIND THE CARET. The
   ghost is a copy of the line laid exactly over the real one, so every figure
   that decides where a letter lands has to be the same in both — and when the
   box grew to 26px the ghost stayed at 22px in a padding of its own, which put
   "cert" a size too small and a few pixels too high at the end of "Autumn Con".
   Set once here; the ghost reads the same two variables. */
.ad-ask-one{--ask-type:26px;--ask-pad:22px 20px}
.ad-ask-one .ad-field input[type=text],
.ad-ask-one .ad-field input[type=url],
.ad-ask-one .ad-field input[type=number],
.ad-ask-one .ad-field input[type=time]{
  font-size:var(--ask-type);padding:var(--ask-pad);line-height:1.3}
.ad-ask-one .ad-field select{font-size:18px;padding:13px 15px}
/* A paragraph, in a box you can see a paragraph in. */
.ad-ask-one .ad-field textarea{font-size:18px;padding:15px 17px;min-height:220px;
  line-height:1.55}
.ad-ask-one .hint{font-size:14px;max-width:66ch;margin-top:9px}

/* Every answer visible, rather than a list to open. The band's sections are
   eleven words: reading them is faster than opening anything. */
.ad-ask-one .ad-pick-row{gap:10px}
.ad-ask-one .ad-pick-one span{min-height:58px;padding:0 26px;font-size:16.5px}

/* ---- a choice with the card to itself ----
   THE TWO ANSWERS TAKE THE WIDTH AND THE HEIGHT, because they are the only
   thing on the screen. They were two small chips against the top-left corner
   with the rest of the card empty white below them, which made the one question
   somebody is being asked look like the least important thing on it. Half the
   card each, deep enough to hold the line that says what the difference is,
   and a target nobody can miss on a phone. */
.ad-ask-one .ad-pick-row{display:grid;grid-template-columns:1fr 1fr;gap:14px}
.ad-ask-one .ad-pick-one.has-why span{min-height:186px;height:100%;padding:24px;
  justify-content:center;gap:14px}
.ad-ask-one .ad-pick-one.has-why b{font-size:23px}
.ad-ask-one .ad-pick-one.has-why i{font-size:15px}

/* THE ANSWERS SIT IN THE MIDDLE OF THE CARD, not against the top of it with the
   floor under them showing. They are the only thing being asked for. */
.ad-card-ask .ad-ask-pick{align-content:center}

/* THE BAND'S BAR, UNDER THE WORD. The gold rule under a heading is the device
   the artwork uses everywhere, and these two words are the heading of their own
   panel — so they carry it, measured from the word the way every other one is.
   Thinner than a page heading's, in proportion to type this size. */
.ad-pick-one.has-why b.rule::after{--bar:4px}
.ad-pick-one.has-why .rule::after{margin-bottom:2px}
@media(max-width:620px){
  /* One above the other: two columns of this depth would each be a column of
     single words down a phone. */
  .ad-ask-one .ad-pick-row{grid-template-columns:1fr}
  .ad-ask-one .ad-pick-one.has-why span{min-height:0}
}

/* ---- the rest of the word ----
   The first answer that starts with what has been typed, drawn in grey behind
   the caret the way a shell finishes a path. A SUGGESTION AND NOT THE VALUE:
   nothing is in the field until somebody takes it, because a box that fills
   itself in is a box that gets saved with a hall nobody chose.

   The ghost is a copy of the line with the typed part made invisible, laid
   exactly over the real one — same font, same padding, same border width — so
   the grey half continues the black half rather than sitting near it. */
/* The wrapper stands where the field stood — it is the grid item now, and
   without this it took one column of twelve and the box came out 60px wide. */
.ad-guess{grid-column:1/-1}
.ad-guess .ad-field{grid-column:auto}
.ad-guess-box{display:block;position:relative}
.ad-guess-ghost{position:absolute;left:0;top:0;right:0;bottom:0;
  padding:var(--ask-pad,16px 18px);
  /* The field's border is two pixels, and a border of one here would shift
     every letter behind the caret by one. */
  border:2px solid transparent;
  font-size:var(--ask-type,22px);line-height:1.3;color:var(--mute);
  pointer-events:none;white-space:pre;overflow:hidden}
.ad-guess-ghost i{font-style:normal;visibility:hidden}

/* ---- taking it ----
   UNDER THE BOX, AND IT SAYS WHAT IT WILL TAKE. It began as a small button laid
   over the right-hand end of the field, which covered the very words it was
   offering and sat on top of any hall name long enough to reach it. A line of
   its own, the width of the field, naming the hall: no overlap, nothing to aim
   at, and it reads as an offer rather than as a control bolted to the box.

   The keys are a shell's and are named on it; the line itself is for the phone,
   where neither of those keys exists. */
.ad-guess-take{display:flex;align-items:center;justify-content:space-between;
  gap:14px;width:100%;margin-top:10px;min-height:48px;padding:0 14px;
  font:inherit;font-size:15px;text-align:left;background:var(--tint);
  border:1px solid var(--line);border-left:3px solid var(--gold);
  color:var(--ink);cursor:pointer;transition:.15s}
.ad-guess-take:hover{border-color:var(--ink);border-left-color:var(--scarlet)}
.ad-guess-take:focus-visible{outline:3px solid var(--scarlet);outline-offset:2px}
.ad-guess-take span{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.ad-guess-take kbd{flex:none;font:inherit;font-size:11.5px;font-weight:900;
  letter-spacing:.14em;text-transform:uppercase;color:var(--mute);
  border:1px solid var(--line);background:#fff;padding:4px 8px}
@media(hover:none){
  /* No Tab key to press on a phone, so the line does not claim there is one. */
  .ad-guess-take kbd{display:none}
}

/* ---- what this question has been answered before ----
   Somebody adding the fifth committee member is about to type "Management
   Committee" for the fifth time. Only shown where the answers genuinely
   repeat — see seenBefore() — or it would be one button per concert title. */
.ad-ask-seen{margin-top:18px;padding-top:16px;border-top:1px solid var(--line)}
.ad-ask-seen p{margin:0 0 9px;font-size:11.5px;font-weight:900;
  letter-spacing:.14em;text-transform:uppercase;color:var(--mute)}
/* TWO ROWS OF FOUR, EVEN. Left to wrap, eight names of wildly different
   lengths came out as a ragged block with a gap at the end of it — "Royal &
   Derngate" beside "The Glasshouse International Centre for Music" beside a
   hole. Four equal columns is a shape; a name too long for its column is cut
   with an ellipsis and says the whole of itself on hover. */
.ad-ask-seen-row{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));
  gap:8px}
.ad-seen{font:inherit;font-size:14.5px;min-height:48px;padding:0 14px;
  background:#fff;border:1px solid var(--line);color:var(--ink);cursor:pointer;
  transition:.15s;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.ad-seen-none{margin:10px 0 0;font-size:13.5px;color:var(--mute)}

@media(max-width:720px){
  /* Two across on a phone, which is as many as a name fits on. */
  .ad-ask-seen-row{grid-template-columns:repeat(2,minmax(0,1fr))}
}
.ad-seen:hover{border-color:var(--scarlet);color:var(--scarlet)}
.ad-seen:focus-visible{outline:3px solid var(--scarlet);outline-offset:2px}
.ad-ask-nope{margin:12px 0 0;font-weight:700;font-size:14px;color:var(--scarlet)}
.ad-ask-end{padding:26px 24px}
.ad-ask-end .lede{margin:0}
.ad-ask-count{font-size:11.5px;font-weight:900;letter-spacing:.14em;
  text-transform:uppercase;color:var(--mute)}
.ad-back-step{font:inherit;font-weight:700;font-size:13px;min-height:44px;
  padding:0 12px;background:none;border:0;color:var(--mute);cursor:pointer}
.ad-back-step:hover{color:var(--ink)}
/* The way on is at the far end from the way back, and the count sits between
   them — so the two are never pressed for each other. */
.ad-card-ask .ad-card-foot .btn{margin-left:auto}
.ad-card-ask .ad-card-foot{gap:12px 16px}
/* Each question arrives rather than appearing. */
.ad-card-ask .ad-card-fields{
  animation:ad-unfold var(--ad-quick,.18s) var(--ad-ease,ease) backwards}
@media(prefers-reduced-motion:reduce){
  .ad-card-ask .ad-card-fields{animation:none}
}

/* ---- two answers, drawn as themselves ----
   A list you have to open to see two things in is a list for the sake of being
   one. Radios underneath — the arrow keys move between them and a screen reader
   says "concert, 1 of 2" — with the buttons drawn over the top.

   The chosen one is scarlet, like every other chosen thing in this admin. */
.ad-pick-row{display:flex;flex-wrap:wrap;gap:8px}
.ad-pick-one{position:relative}
.ad-pick-one input{position:absolute;inset:0;width:100%;height:100%;
  margin:0;opacity:0;cursor:pointer}
.ad-pick-one span{display:inline-flex;align-items:center;justify-content:center;
  min-height:48px;padding:0 22px;font-weight:700;font-size:15px;
  background:#fff;border:2px solid var(--line);color:var(--ink);
  transition:.15s;pointer-events:none}
.ad-pick-one input:hover + span{border-color:var(--ink)}
.ad-pick-one input:checked + span{background:var(--scarlet);
  border-color:var(--scarlet);color:#fff}

/* ---- EXPLAIN WHEN ASKING, NAME WHEN EDITING -------------------------------
   The line under each answer is the difference between a concert and a contest,
   and it is worth a panel each on the card that asks the question for the first
   time. On the form it is two paragraphs about something already answered,
   taking a third of the height of a form with eleven fields in it — so there
   they are the two words, as they were. */
.ad-card-fields:not(.ad-ask-one) .ad-pick-one.has-why i{display:none}
.ad-card-fields:not(.ad-ask-one) .ad-pick-one.has-why span{
  flex-direction:row;align-items:center;justify-content:center;
  min-height:48px;padding:0 22px}
.ad-card-fields:not(.ad-ask-one) .ad-pick-one.has-why b{font-size:15px;
  letter-spacing:.06em}
.ad-card-fields:not(.ad-ask-one) .ad-pick-one.has-why b.rule::after{display:none}
.ad-ask-one .ad-pick-row:has(.has-why){display:grid;grid-template-columns:1fr 1fr;gap:12px}

/* An option that carries a line of its own is a block, not a chip: the word
   above, the line under it, both left-aligned so the two options read as two
   paragraphs to choose between rather than as two labels. */
.ad-pick-one.has-why span{flex-direction:column;align-items:flex-start;
  justify-content:flex-start;gap:9px;padding:16px;text-align:left;height:100%}
.ad-pick-one.has-why b{font-size:17px;font-weight:900;letter-spacing:.04em;
  text-transform:uppercase;line-height:1}
.ad-pick-one.has-why i{font-style:normal;font-weight:500;font-size:13.5px;
  line-height:1.5;color:var(--mute);
  /* The row sits inside a <label>, and a field's label is capitals — which the
     sentence inside the button would otherwise inherit and be shouted in. */
  text-transform:none;letter-spacing:normal}
.ad-pick-one.has-why input:checked + span i{color:rgba(255,255,255,.92)}
.ad-pick-one input:focus-visible + span{outline:3px solid var(--scarlet);
  outline-offset:3px}

/* ---- asking, in the band's own words ---------------------------------------
   The browser's own box says "localhost:8080 says" in the machine's own font,
   and on a phone it arrives from the top of the screen like a warning about
   something going wrong. This is the same card everything else in the admin
   opens in, at the width of a question rather than of a form. */
.ad-ask{width:min(520px,calc(100vw - 32px))}
.ad-ask .ad-card-fields{display:block;padding:22px 24px 0}
.ad-ask .ad-card-fields > p{margin:0 0 14px;max-width:52ch}
.ad-ask .ad-field{margin-bottom:14px}
.ad-ask .ad-card-foot{margin-top:6px}
.ad-ask .ad-ask-nope{color:var(--scarlet);font-weight:700}

/* Something to be read out loud and typed in somewhere else: big, spaced, and
   in the face the password boxes use, so an l and a 1 cannot be confused —
   though the maker avoids both anyway. */
.ad-ask-copy{margin:4px 0 18px}
.ad-ask-copy code{display:block;padding:16px 18px;
  font-family:Verdana,Tahoma,'DejaVu Sans',monospace;
  font-size:22px;letter-spacing:.06em;text-align:center;
  background:var(--tint);border:2px solid var(--line);
  user-select:all}

/* ---- the day, the time and all-day, as one line ----------------------------
   A DATE IS A CALENDAR AND A CALENDAR IS HALF A CARD. Drawn open on a form of
   eleven fields, the first answer filled the screen and everything after it was
   below the fold; and it was open whether or not it needed touching, which on
   an entry somebody is editing to fix the venue is every time but one.

   So it is a line: what it says now on the left, the way it will read on the
   site, and a word on the right that opens it. Open where the date is not there
   yet, because a required field hiding behind a line saying "Not set" is a form
   that refuses to save without saying where. */
.ad-when-set{border:1px solid var(--line);background:var(--tint)}
.ad-when-say{display:flex;align-items:center;gap:8px 18px;flex-wrap:wrap;
  width:100%;min-height:56px;padding:12px 16px;font:inherit;text-align:left;
  background:none;border:0;border-left:3px solid var(--gold);color:var(--ink);
  cursor:pointer;transition:.15s}
.ad-when-say:hover{background:#fff;border-left-color:var(--scarlet)}
.ad-when-say:focus-visible{outline:3px solid var(--scarlet);outline-offset:-3px}
.ad-when-lab{font-weight:900;font-size:11.5px;letter-spacing:.14em;
  text-transform:uppercase;color:var(--mute)}
.ad-when-val{font-weight:700;font-size:16px}
.ad-when-val em{font-style:normal;color:var(--scarlet)}
.ad-when-do{margin-left:auto;font-weight:700;font-size:12.5px;letter-spacing:.09em;
  text-transform:uppercase;color:var(--scarlet)}
.ad-when-in{display:grid;gap:18px 26px;align-items:start;
  padding:8px 16px 18px;background:#fff;border-top:1px solid var(--line)}
/* The calendar is a month wide whatever else happens; everything else in the
   bracket stands beside it in a column of its own, at the top rather than
   spread down the side of a six-row month. */
.ad-when-side{display:grid;gap:16px;align-content:start}
/* A field carries a width class — .f-md, .f-lg — which spans columns of the
   twelve the card is built on. Inside this two-column bracket those spans
   invent tracks of nothing and push the second column onto a row of its own,
   so they are overruled here rather than being made conditional everywhere. */
.ad-when-in > .ad-field,
.ad-when-in > .ad-when-side{grid-column:1}
@media(min-width:820px){
  .ad-when-in{grid-template-columns:minmax(0,7fr) minmax(0,5fr)}
  .ad-when-in > .ad-when-side{grid-column:2;grid-row:1}
}

/* ---- the clock -------------------------------------------------------------
   THE FACE IS A CIRCLE BECAUSE A CLOCK IS A CIRCLE — the same argument the play
   button on the Listen page makes, and the only other place this site makes it.
   It is drawn rather than cornered: an SVG circle, not a rounded box, so the
   rule about square corners is untouched and everything on the face is square.

   The shape is the one every phone uses, because that is the one everybody has
   already learnt: the time written out large at the top, the part you are
   setting picked out in scarlet, and the dial under it. */
.ad-clock{display:grid;gap:14px;justify-items:start;
  max-width:280px}

.ad-clock-read{display:flex;align-items:center;gap:2px}
.ad-clock-part{min-width:60px;min-height:56px;padding:0 6px;font:inherit;
  font-weight:900;font-size:40px;line-height:1;letter-spacing:-.01em;
  background:var(--tint);border:0;color:var(--mute);
  cursor:pointer;transition:.15s}
.ad-clock-part:hover{color:var(--ink)}
.ad-clock-part.on{background:var(--scarlet);color:#fff}
.ad-clock-part:focus-visible{outline:3px solid var(--ink);outline-offset:2px}
.ad-clock-colon{font-weight:900;font-size:34px;line-height:1;padding:0 4px;
  color:var(--mute)}
/* am and pm are one control of two halves, stacked, the way a phone's is. */
.ad-clock-halves{display:grid;gap:2px;margin-left:12px}
.ad-clock-half{min-width:54px;min-height:27px;padding:0 8px;font:inherit;
  font-weight:700;font-size:13px;text-transform:lowercase;
  background:#fff;border:2px solid var(--line);color:var(--mute);
  cursor:pointer;transition:.15s}
.ad-clock-half:hover{border-color:var(--royal);color:var(--royal)}
.ad-clock-half.on{background:var(--scarlet);border-color:var(--scarlet);color:#fff}
.ad-clock-half:focus-visible{outline:3px solid var(--scarlet);outline-offset:2px}

.ad-clock-face{position:relative;width:min(258px,72vw);aspect-ratio:1;
  touch-action:none;cursor:pointer}
.ad-clock-face svg{display:block;width:100%;height:100%;overflow:visible}
/* A PALE FACE, NOT AN INK ONE. A black disc the size of a hand is the heaviest
   thing on a white form by a long way, and it read as a hole in the card rather
   than as a clock. Scarlet leads on white, which is the rule everywhere else
   here, so the face is the tint the cards use and the answer is scarlet on it. */
.ad-clock-dial{fill:var(--tint);stroke:var(--line);stroke-width:1}
/* Two hands, and the one being set is the bright one. The other stays where it
   is as a reminder of what the rest of the answer already is. */
.ad-clock-hand{stroke:var(--line);stroke-width:2.4;stroke-linecap:round;
  transform-origin:50px 50px;transition:transform .22s cubic-bezier(.2,.8,.25,1)}
.ad-clock-hand.is-lead{stroke:var(--scarlet);stroke-width:3}
/* The end of the hand being set is a disc under the number it is on, which is
   what makes the dial read as one continuous control rather than as twelve
   buttons with a line behind them. */
.ad-clock-knob{fill:var(--scarlet);opacity:.14;transform-origin:50px 50px;
  transform-box:view-box;transition:transform .22s cubic-bezier(.2,.8,.25,1)}
.ad-clock-knob{cy:12}
.ad-clock-pin{fill:var(--scarlet)}
.ad-clock.is-unset .ad-clock-hand,
.ad-clock.is-unset .ad-clock-knob{opacity:.12}

/* The twelve marks are squares over the face. 30px is under the 44 this admin
   holds itself to, and it is the one place that cannot be helped: twelve
   targets on one dial. The hand can be dragged instead, which is the bigger
   target — the whole face. */
.ad-clock-n{position:absolute;transform:translate(-50%,-50%);
  min-width:32px;min-height:32px;padding:0;font:inherit;font-weight:700;
  font-size:14px;line-height:1;background:none;border:0;color:var(--ink);
  cursor:pointer;transition:color .15s,background .15s}
.ad-clock-n:hover{background:#fff;color:var(--royal)}
.ad-clock-n.on{color:#fff;background:var(--scarlet);font-weight:900}
.ad-clock-n:focus-visible{outline:3px solid var(--scarlet);outline-offset:1px}

.ad-clock-clear{justify-self:start;white-space:nowrap;padding:6px 0;font:inherit;
  font-size:13.5px;background:none;border:0;border-bottom:2px solid var(--line);
  color:var(--mute);cursor:pointer;transition:.15s}
.ad-clock-clear:hover{color:var(--scarlet);border-bottom-color:var(--scarlet)}

/* =============================================================================
   THE CALENDAR
   =============================================================================
   The browser's own date box is three little spinners in whatever order the
   machine's locale says. This is the band's diary instead: Monday first, six
   rows always so the card does not change height as the months go by, and the
   two things that actually go wrong marked on it — a concert put on a Sunday,
   and two concerts put on one afternoon.

   IT IS NOT A WIDGET IN A BOX. The first version had a black title bar with the
   month centred in it and an arrow at each end, a hairline round the outside
   and a grey footer strip — the shape every date picker on the internet had in
   about 2010, and it read as one. This one is a page of a diary: the month set
   in the band's own display type, the days in open space with nothing ruled
   round them, and one hairline where the week begins.
   ========================================================================== */
.ad-cal{max-width:360px}

.ad-cal-top{display:flex;align-items:baseline;justify-content:space-between;
  gap:16px;padding:2px 0 10px}
.ad-cal-month{font-size:23px;font-weight:900;letter-spacing:-.01em;
  line-height:1.1;color:var(--ink)}
/* The year is the quiet half of it: you know which year it is, and you are
   looking for a month. */
.ad-cal-month span{color:var(--mute);font-weight:700}

.ad-cal-steps{display:flex;gap:4px;flex:none}
.ad-cal-step{width:40px;height:40px;flex:none;font:inherit;font-size:20px;
  line-height:1;background:none;border:1px solid var(--line);color:var(--ink);
  cursor:pointer;transition:.15s}
.ad-cal-step:hover{background:var(--ink);border-color:var(--ink);color:#fff}
.ad-cal-step:focus-visible{outline:3px solid var(--scarlet);outline-offset:2px}

.ad-cal-week{display:grid;grid-template-columns:repeat(7,1fr);
  padding:0 0 8px;border-bottom:1px solid var(--line);
  font-size:11.5px;font-weight:900;letter-spacing:.14em;text-transform:uppercase;
  text-align:center;color:var(--mute)}
/* SATURDAY IS THE BAND'S DAY, said in the heading rather than by tinting the
   whole column. A tinted column reads as a spreadsheet; a scarlet letter reads
   as "look here first", which is what it is for. */
.ad-cal-week .is-sat{color:var(--scarlet)}

.ad-cal-days{display:grid;grid-template-columns:repeat(7,1fr);
  gap:2px;padding:6px 0 0}

.ad-cal-day{position:relative;aspect-ratio:1;display:grid;place-items:center;
  font:inherit;font-size:15px;font-weight:500;background:none;border:0;
  color:var(--ink);cursor:pointer;transition:background .12s,color .12s}
.ad-cal-day:hover{background:var(--tint)}
.ad-cal-day:focus-visible{outline:3px solid var(--scarlet);outline-offset:-3px}

/* Saturdays carry the weight instead of a background. */
.ad-cal-day.is-sat{font-weight:900}

/* Already gone. Quieter, and still choosable — a concert entered after the fact
   is a real thing, and refusing it would only teach people to lie about it. */
.ad-cal-day.is-gone{color:var(--mute)}

/* The days either side of the month, in their own places. Quiet enough not to
   be mistaken for this month and solid enough to be aimed at. */
.ad-cal-day.is-spill{color:#C3B8B3;font-weight:500}

/* Today, under the number, in the band's gold. */
.ad-cal-day.is-today b{box-shadow:0 3px 0 var(--gold)}

/* A day the band is already out on: a scarlet bar under the number, the same
   mark the site puts under a heading. The dot it started as was a full stop.
   This is the whole point of drawing a calendar rather than a box — two
   concerts on one afternoon is invisible in "2026-09-06" and obvious here. */
.ad-cal-day.is-busy::after{content:'';position:absolute;left:50%;bottom:6px;
  width:14px;height:3px;margin-left:-7px;background:var(--scarlet)}

.ad-cal-day.on{background:var(--scarlet);color:#fff;font-weight:900}
.ad-cal-day.on:hover{background:var(--royal)}
.ad-cal-day.on::after{background:var(--gold)}

.ad-cal-said{margin:14px 0 0;padding:12px 0 0;border-top:1px solid var(--line)}

/* IN THE WALKTHROUGH IT IS THE ONLY THING ON THE SCREEN, so it takes the whole
   of it. At 340px in an 880px card it sat in the corner like something that had
   not finished loading.

   The cells stop being squares there and become the wide rows a wall calendar
   has — a square cell across a full-width card would be 110px of nothing with a
   number in the middle. */
.ad-ask-one .ad-cal{max-width:none;width:100%}
.ad-ask-one .ad-cal-month{font-size:30px}
.ad-ask-one .ad-cal-week{font-size:12px;padding-bottom:10px}
.ad-ask-one .ad-cal-days{gap:3px;padding-top:8px}
.ad-ask-one .ad-cal-day{aspect-ratio:auto;min-height:58px;font-size:18px}
.ad-ask-one .ad-cal-day.is-busy::after{width:18px;height:3px;margin-left:-9px;
  bottom:9px}
.ad-ask-one .ad-cal-said{font-size:16.5px;margin-top:16px}

/* ---- what the answer means, under the answer ----
   The day of the week under a date, and what the posters will bill an address
   as. Quiet: it is the answer read back, not another thing to fill in. */
.ad-says{margin:7px 0 0;font-size:13.5px;color:var(--mute);min-height:1.2em}
.ad-says b{color:var(--ink);font-weight:700}
.ad-ask-one .ad-says{font-size:15px}

/* ---- the foot ----
   The ways of getting rid of the thing sit at one end and the way of being
   finished with it at the other, so the two are never pressed for each other. */
.ad-card-foot{position:sticky;bottom:0;z-index:3;
  display:flex;flex-wrap:wrap;align-items:center;gap:10px 14px;
  padding:16px 24px;border-top:1px solid var(--line);background:var(--tint)}
.ad-card-foot .btn{margin-left:auto}
.ad-card-foot .ad-remove{margin:0}

@media(prefers-reduced-motion:reduce){
  .ad-card[open],.ad-card[open]::backdrop{animation:none}
}

/* ---- what has already happened ----
   A diary is mostly the past: seven concerts this season under ninety that have
   gone. They fold away a week after they happen — a concert is still being
   talked about the week after it, and that is when the photographs and the
   result go in. */
.ad-past{margin-top:18px;border-top:1px solid var(--line);padding-top:16px}
.ad-past-head{display:inline-flex;align-items:center;gap:10px;min-height:44px;
  padding:0 14px;background:#fff;border:1px solid var(--line);font:inherit;
  font-size:14px;color:var(--mute);cursor:pointer;transition:.15s}
.ad-past-head:hover{border-color:var(--ink);color:var(--ink)}
.ad-past-head b{font-weight:900;color:var(--ink)}
.ad-past-more{font-weight:700;font-size:12.5px;letter-spacing:.09em;
  text-transform:uppercase;color:var(--scarlet)}
.ad-past-list:not([hidden]){margin-top:12px;
  animation:ad-unfold var(--ad-quick,.18s) var(--ad-ease,ease) backwards}

/* The row itself says it can be opened, on the right where the eye ends up. */
.ad-open{flex:none;font-weight:700;font-size:12.5px;letter-spacing:.09em;
  text-transform:uppercase;color:var(--mute)}
.ad-head:hover .ad-open{color:var(--scarlet)}

/* ---- the people screen ---- */
.ad-person{display:flex;flex-wrap:wrap;gap:16px 22px;align-items:flex-start;
  padding:16px 0}
.ad-person-who{flex:1 1 220px;min-width:0;display:flex;flex-direction:column;gap:3px}
.ad-person-who b{font-size:16px}
.ad-person-who span{font-size:13.5px;color:var(--mute)}
.ad-person-who .ad-chip{align-self:flex-start;margin-top:3px}
.ad-person-seen{font-size:12.5px}
.ad-person-ticks{flex:1 1 240px;display:grid;gap:4px}
.ad-person-do{flex:0 0 auto;display:flex;flex-direction:column;gap:6px}
.ad-person-do button{min-height:44px;padding:0 14px;font:inherit;font-size:12.5px;
  font-weight:700;letter-spacing:.09em;text-transform:uppercase;
  background:#fff;color:var(--ink);border:1px solid var(--line);cursor:pointer}
.ad-person-do button:hover{border-color:var(--ink)}
.ad-tickbox{display:flex;align-items:center;gap:9px;min-height:32px;
  font-size:14px;cursor:pointer}
.ad-tickbox input{width:20px;height:20px;flex:0 0 auto;accent-color:var(--scarlet)}
.ad-entry.past .ad-person{opacity:.6}

/* =============================================================================
   A FACE
   =============================================================================
   Most people who use this admin are in the band, and their photograph is
   already on the website. So an account does not carry its own: it carries the
   name of the player it belongs to, and the picture follows from the Players
   list — one photograph of each person, kept by whoever looks after the site.
   functions/_lib/faces.js decides which; this only draws it.

   INITIALS WHEN THERE IS NONE, not a grey outline of a head. Thirteen people
   who know each other are told more by two letters than by a silhouette, and a
   silhouette on every row would say only that nobody had got round to it.

   SQUARE, like everything else on this site. A round avatar is the one place a
   brand with no rounded corners in it always seems to acquire one.

   CALLED .ad-who, NOT .ad-face. There is already an .ad-face on this site — the
   thumbnail against a player in the content lists — declared later in this file,
   so a second one of the same name silently won every property they shared:
   104px squares came out at 46 and the ink screen's frame came out beige. The
   collision cost twenty minutes and would have cost an afternoon if the sizes
   had been closer.

   Royal Red on the initials: small furniture on white, which is the job the
   guidelines give the darker red. 7.64:1 on the tint behind it. */
.ad-who{display:grid;place-items:center;flex:none;overflow:hidden;
  width:44px;height:44px;background:var(--tint);border:1px solid var(--line);
  color:var(--royal)}
.ad-who img{display:block;width:100%;height:100%;object-fit:cover}
.ad-who b{font-weight:900;font-size:15px;letter-spacing:.03em;line-height:1}

.ad-who-sm{width:40px;height:40px}
.ad-who-sm b{font-size:14px}
.ad-who-md{width:64px;height:64px}
.ad-who-md b{font-size:21px}
.ad-who-lg{width:104px;height:104px}
.ad-who-lg b{font-size:34px}

/* On the sign-out tile it stands where the mark stands, so it takes the mark's
   box rather than a size of its own — 76px on the front page, 52 in a wide
   tile, and the foot row spans it across both rows exactly as it does the
   plate. */
.ad-who-tile{width:76px;height:76px;margin-bottom:18px}
.ad-who-tile b{font-size:26px}
.ad-tile.wide .ad-who-tile{width:52px;height:52px;margin:0}
.ad-tile.wide .ad-who-tile b{font-size:18px}
.ad-home-foot .ad-who-tile{grid-row:1/3;align-self:center}

/* ---- the welcome ----
   On ink, where the accent is gold: a tint square with royal initials would be
   a piece of the white page dropped onto a dark screen. The picture itself
   needs no help — it is a photograph — so only the frame and the initials
   change. */
/* ---- on ink ----
   The frame and the initials change; the photograph needs no help. Used by the
   welcome and by the line under the save button, both of which sit on the ink
   banner. */
.ad-who-dark{background:rgba(255,255,255,.06);
  border-color:rgba(255,255,255,.28);color:var(--gold)}
.ad-welcome-face{margin:0 0 18px;background:rgba(255,255,255,.06);
  border-color:rgba(255,255,255,.28);color:var(--gold)}

/* ---- setting one, on the People screen ---- */
.ad-person-face{flex:1 1 100%;display:flex;flex-wrap:wrap;align-items:center;
  gap:10px 16px;padding-top:4px}
.ad-who-pick{display:flex;align-items:center;gap:9px;font-size:11.5px;
  font-weight:900;letter-spacing:.14em;text-transform:uppercase;color:var(--mute)}
.ad-who-pick select{font:inherit;font-size:14.5px;font-weight:500;
  letter-spacing:0;text-transform:none;color:var(--ink);min-height:44px;
  padding:0 10px;border:1px solid var(--line);background:#fff;border-radius:0;
  max-width:min(100%,20em)}
/* The upload is the site's own file-input button, not a second one. */
.ad-who-up span{font-size:13px;padding:0 13px;border-width:2px}
.ad-who-clear{font:inherit;font-weight:700;font-size:13px;letter-spacing:.04em;
  min-height:44px;padding:0 4px;background:none;border:0;cursor:pointer;
  color:var(--scarlet);text-decoration:underline}
.ad-who-clear:hover{color:var(--royal)}
.ad-who-say{font-size:13px;color:var(--mute);min-height:1.2em}

/* ---- what changed ---- */
.ad-diff{width:100%;border-collapse:collapse;font-size:13.5px}
.ad-diff th{text-align:left;font-weight:700;padding:7px 12px 7px 0;
  vertical-align:top;width:40%}
.ad-diff td{padding:7px 12px 7px 0;vertical-align:top;width:30%}
.ad-diff tr+tr th,.ad-diff tr+tr td{border-top:1px solid var(--line)}
.ad-diff .was{color:var(--mute);text-decoration:line-through}
.ad-diff .now{color:var(--ink);font-weight:700}

/* =============================================================================
   THE ANALYTICS SCREEN
   =============================================================================
   It holds more than any other screen in the admin, and for a while it showed
   all of it at once: nine headings down one column, every one at the same
   volume, four screens deep. Nothing was wrong with any single part — the fault
   was that the screen had no opinion about what mattered.

   So it is now read from the top down, in three sizes.

     ONE SENTENCE  — what happened, in the words somebody would use out loud.
     FOUR FIGURES  — and pressing one draws it on the chart underneath.
     FIVE CARDS    — one shape repeated, each showing one face at a time.

   Nothing was taken away. Every list that was on the screen is still on it, and
   the download still carries the lot. What changed is that the reader is shown
   the first five rows and chooses the rest, rather than being handed
   four hundred and made to find the twelve that mattered.
   ========================================================================== */

/* ---- choosing the stretch of time ----
   Presets for the questions somebody actually asks, and two date boxes for the
   one they have not thought of. The presets are not a select: six words visible
   at once are quicker to compare than six hidden behind a click, and on a phone
   they wrap into rows rather than opening a system picker over the page. */
.an-range{display:flex;flex-wrap:wrap;align-items:flex-end;
  justify-content:space-between;gap:14px 22px;margin:0 0 22px;
  padding-bottom:18px;border-bottom:1px solid var(--line)}
.an-presets{display:flex;flex-wrap:wrap;gap:6px}
.an-when-btn{font:inherit;font-weight:700;font-size:12.5px;letter-spacing:.09em;
  text-transform:uppercase;min-height:44px;padding:0 13px;cursor:pointer;
  background:none;border:2px solid var(--line);color:var(--ink);
  transition:border-color .16s,background .16s,color .16s}
/* HOVER IS INK, CHOSEN IS SCARLET — the admin's own tab bar (.ad-tab) has said
   so since it was built, and this screen had it the other way round. Filled
   rather than merely outlined either way: a border a shade darker than its
   neighbours is not a state anybody notices. */
.an-when-btn:hover{border-color:var(--ink);color:var(--ink)}
.an-when-btn.on{background:var(--scarlet);border-color:var(--scarlet);color:#fff}

.an-dates{display:flex;flex-wrap:wrap;align-items:center;gap:10px;
  font-size:12.5px;font-weight:700;letter-spacing:.09em;text-transform:uppercase;
  color:var(--mute)}
.an-dates label{display:flex;align-items:center;gap:7px}
.an-dates input{font:inherit;font-size:14px;letter-spacing:0;text-transform:none;
  color:var(--ink);min-height:44px;padding:0 10px;
  border:1px solid var(--line);background:#fff}

/* While the figures are being fetched. Faded rather than replaced by a spinner:
   the numbers on screen are the ones being replaced, and dimming them says
   "these are on their way out" without taking away what there is to read. */
#adminBody.is-waiting{opacity:.55;pointer-events:none;transition:opacity .18s}

.an-each{font-weight:500;letter-spacing:0;text-transform:none;color:var(--mute)}

/* ---- the sentence at the top ----
   The whole screen in one line, in the language somebody would use to say it
   out loud. A reader who stops here has still been told the thing they came
   for; everything below is the working. */
.an-say{max-width:62ch}
.an-say b{font-weight:900}
/* What a visit is, and what the figures are NOT. Set small and grey on purpose:
   it is the small print under the sentence, and at body size it competed with
   the sentence it was explaining. Sessions and page views are the pair everybody
   confuses, so the definition stays on the screen rather than in a manual. */
.an-mean,.an-soft{max-width:74ch;margin-top:10px;font-size:13.5px;
  line-height:1.55;color:var(--mute)}

/* ---- what it is narrowed to ----
   Said on the screen rather than left to be remembered. A filtered figure that
   looks like a total is the most quotable wrong number a page like this can
   produce. Each chip removes its own filter; the last removes them all. */
.an-chips{display:flex;flex-wrap:wrap;align-items:center;gap:8px;
  margin:0 0 20px}
.an-chips-say{font-size:11.5px;font-weight:900;letter-spacing:.14em;
  text-transform:uppercase;color:var(--mute)}
.an-chip{font:inherit;font-weight:700;font-size:13px;min-height:44px;
  padding:0 12px;cursor:pointer;background:var(--scarlet);color:#fff;border:0;
  transition:background .16s}
.an-chip:hover{background:var(--royal)}
.an-chip-all{background:none;color:var(--mute);border:2px solid var(--line)}
.an-chip-all:hover{background:none;border-color:var(--royal);color:var(--royal)}

/* ---- the headline figures, which ARE the chart's controls ----
   There used to be a strip of figures and, below it, a separate pair of buttons
   saying which of them the chart was drawing: two places to look for one idea.
   Pressing the figure itself is the same gesture with nothing to learn.

   THE PRESSED ONE IS FILLED WITH INK AND CARRIES A SCARLET EDGE ALONG THE TOP,
   so which figure the chart is drawing survives being read in a hurry, in
   greyscale, or by somebody who cannot separate scarlet from grey. */
.an-heads{display:grid;grid-template-columns:repeat(auto-fit,minmax(200px,1fr));
  gap:14px;margin:4px 0 10px}
.an-big{position:relative;display:block;width:100%;text-align:left;font:inherit;
  color:inherit;border:1px solid var(--line);background:var(--tint);
  padding:18px 20px;transition:background .18s,border-color .18s,transform .18s}
button.an-big{cursor:pointer}
/* The same lift and the same lightening as every other tile in this admin —
   the figures are pressable, so they behave like the things that are. */
/* :not(.on), or hovering the chosen figure would lighten it back to white —
   the hover rule is more specific than the chosen one and would win. */
button.an-big:not(.on):hover{background:#fff;border-color:var(--royal)}
button.an-big:hover{transform:translateY(-3px)}
button.an-big:focus-visible{outline:3px solid var(--scarlet);outline-offset:2px}
.an-big::before{content:'';position:absolute;left:-1px;right:-1px;top:-1px;
  height:6px;background:var(--gold);transform:scaleX(0);transform-origin:left;
  transition:transform .22s var(--ad-ease,ease)}
/* SCARLET, NOT INK. Scarlet is what this site fills a chosen thing with and
   ink is what it fills a hovered one with — the admin's tab bar has done both
   since it was built. The gold bar above it sits on scarlet exactly as the
   header's gold rule does. */
.an-big.on{background:var(--scarlet);border-color:var(--scarlet);color:#fff}
.an-big.on::before{transform:scaleX(1)}
.an-big b{display:block;font-size:clamp(28px,3.6vw,42px);line-height:1;
  font-weight:900;letter-spacing:-.01em;font-variant-numeric:tabular-nums}
.an-big-what{display:block;margin-top:6px;font-size:11.5px;font-weight:900;
  letter-spacing:.14em;text-transform:uppercase;color:var(--mute)}
/* WHITE, NOT GOLD. Gold on scarlet measures 3.75:1 — enough for a bar or a
   piece of display type, not for a 12px label. Gold leads on ink; on scarlet,
   small text is white. */
.an-big.on .an-big-what{color:rgba(255,255,255,.92)}
.an-big-move{display:block;margin-top:12px}
/* The direction is a word AND a colour, never a colour alone: "+34%" says it
   without anybody having to know that scarlet means up, and roughly one man in
   twelve cannot reliably tell this site's scarlet from a green anyway.

   ON INK IT IS GOLD, not scarlet — scarlet on ink measures 3.07:1, the bare
   floor for a graphic and it looks like it. Scarlet leads on white; gold leads
   on ink, everywhere on this site. */
.an-move{display:inline-block;font-weight:900;font-size:14px}
.an-move.up{color:var(--scarlet)}
.an-move.down{color:var(--mute)}
/* Level is neither. It used to be scarlet, which is this site's word for "more"
   — so a month that had not moved was coloured as though it had. */
.an-move.level{color:var(--ink)}
.an-big.on .an-move.up,.an-big.on .an-move.level{color:#fff}
/* The site's own way of quietening text on a dark surface — .dark p is
   rgba(255,255,255,.82) — rather than a grey mixed for this one screen. */
.an-big.on .an-move.down,.an-big.on .an-was{color:rgba(255,255,255,.82)}
.an-was{margin-left:8px;font-size:13px;color:var(--mute)}
.an-soft{margin:0 0 18px}

/* ---- what the chart is drawing, and how it is grouped ----
   Which measure is a choice the browser can make on its own — every one of them
   is already here for every bucket. The grouping is not: it decides what the
   database was asked, so it costs a round trip and sits apart from the thing
   that does not. */
.an-chart-bar{display:flex;flex-wrap:wrap;align-items:center;
  justify-content:space-between;gap:8px 20px;margin:14px 0 4px}
.an-drawing{margin:0;font-size:13px;color:var(--mute)}
.an-drawing b{color:var(--ink);font-weight:900}
.an-by{font-size:11.5px;font-weight:900;letter-spacing:.14em;text-transform:uppercase;
  color:var(--mute);display:flex;align-items:center;gap:8px}
.an-by select{font:inherit;font-size:14px;letter-spacing:0;text-transform:none;
  font-weight:500;color:var(--ink);min-height:40px;padding:0 8px;
  border:1px solid var(--line);background:#fff}

/* ---- the line, once there are too many points for bars ----
   Thin, and one pixel whatever the width: the drawing is stretched to fit its
   box, so without non-scaling-stroke a line drawn a pixel wide comes out three
   on a laptop and hairline on a phone. */
.an-line{height:170px;margin:6px 0 0;border-bottom:2px solid var(--line);
  cursor:crosshair;touch-action:pan-y}
.an-line svg{display:block;width:100%;height:100%;overflow:visible}
/* IT DRAWS ITSELF, left to right, in half a second. The stylesheet cannot know
   how long the path is and the length changes with every range asked for — so
   the path is told to call itself one unit long (pathLength="1" in admin.js),
   and a dash one unit long held back by one unit is a line that has not started
   yet. */
.an-line-path{fill:none;stroke:var(--scarlet);stroke-width:1.5;
  vector-effect:non-scaling-stroke;stroke-linejoin:round;stroke-linecap:round;
  stroke-dasharray:1;stroke-dashoffset:1;animation:an-draw .62s ease-out forwards}
/* Faint. The line is the reading, and a solid wedge under a year of traffic
   makes it harder to follow rather than easier. */
.an-line-fill{fill:var(--scarlet);opacity:.07;stroke:none;
  animation:an-fade .7s ease-out backwards;animation-delay:.15s}
.an-line-cursor{stroke:var(--royal);stroke-width:1;vector-effect:non-scaling-stroke;
  opacity:.45}
/* Every point carries a dot, invisible until it is the one being pointed at —
   drawing them all would turn a smooth line back into a comb. */
.an-dot{fill:var(--scarlet);opacity:0;transform-box:fill-box;
  transform-origin:center;transition:opacity .12s}
.an-dot.on{opacity:1}
/* SCARLET, NOT THE SITE'S GOLD RING, and only because of the surface. Gold on
   white measures 1.77:1 — a focus ring nobody can see is not a focus ring, and
   the standard asks for 3:1 on a mark like this. Scarlet on white is 6.17:1.
   The gold ring is right everywhere it sits on scarlet or ink; here it is not,
   which is why the admin's other rings are scarlet too. */
.an-line:focus-visible{outline:3px solid var(--scarlet);outline-offset:3px}

.an-read{margin:10px 0 0;min-height:1.5em;font-size:14.5px}
.an-read b{font-weight:900}
.an-read-was{margin-left:10px;color:var(--mute);font-size:13px}

/* ---- the stretch before ----
   Drawn behind the current one and deliberately hard to mistake for it: dashed,
   thin, grey. A second line as strong as the first is two charts on one axis,
   and the reader has to work out which is which before they can read either.

   ITS DASHES ARE ITS OWN and must stay that way, which is why it fades in
   instead of drawing itself: the drawing trick above works by taking the dash
   pattern over, and a comparison line that arrived solid would read as a second
   reading rather than as context. */
.an-line-was{fill:none;stroke:var(--mute);stroke-width:1;opacity:.55;
  stroke-dasharray:4 4;vector-effect:non-scaling-stroke;stroke-linejoin:round;
  animation:an-fade .5s ease-out backwards;animation-delay:.3s}

.an-key{display:flex;align-items:center;gap:8px;margin:8px 0 0;
  font-size:12.5px;color:var(--mute)}
.an-key-was{display:block;width:26px;height:0;flex:none;
  border-top:1px dashed var(--mute)}

/* Sits with the SHOW button and is deliberately the quieter of the two: taking
   the figures away is a thing somebody does once a quarter for a committee
   paper, not the reason they opened the screen. */
.an-get:disabled{opacity:.4;cursor:not-allowed}

/* ---- the cards ----
   ONE SHAPE, REPEATED, and each shows one face at a time. Five cards with a
   name and a row of tabs is one thing to learn; nine headings down a column is
   nine things to weigh up, all of them shouting equally.

   align-items:start, so a card with eight rows does not stretch the one beside
   it to match — a stretched card is mostly empty space with a rule round it. */
/* min(100%,400px), NOT 400px. A bare minimum in minmax() is a floor the grid
   keeps even when the column has less room than that — so on a 390px phone the
   cards stayed 400 wide and the whole page could be scrolled sideways by 34px.
   Measured, not guessed: the document was 424px across a 390px window. */
/* ---- how much scarlet a card carries ----
   FULL STRENGTH BELONGS TO THE CHART and to the figure you have chosen — those
   are the reading. Four cards of ranked lists at the same strength turned the
   screen into a wall of red, and a colour used for everything stops pointing at
   anything.

   So the lists are drawn in a wash of the same scarlet rather than in a second
   colour: one red, at two strengths. Measured against the track it sits in —
   #E5A5AB on #E6DDD8 is 1.52:1, which is a bar you can see at a glance; the
   figure is printed beside every one of them in any case, so the bar is the
   shape of the answer rather than the answer itself. */
.an-cards{--soft:rgba(190,29,46,.4);
  display:grid;
  grid-template-columns:repeat(auto-fit,minmax(min(100%,400px),1fr));
  gap:18px;align-items:start;margin:30px 0 0}
.an-card{border:1px solid var(--line);background:#fff;padding:18px 20px 22px;
  animation:ad-pop var(--ad-calm,.26s) var(--ad-ease,ease) backwards;
  animation-delay:var(--in,0ms)}
/* Deliberately NOT given the gold bar the site puts under a heading. That bar
   is measured from the words beneath it and its gap equals its own thickness —
   a device built for a heading with a paragraph under it, not for one sharing a
   line with a row of tabs. A plain rule under the whole header keeps the card's
   parts together without inventing a second version of the band's own mark. */
.an-card-top{display:flex;flex-wrap:wrap;align-items:center;
  justify-content:space-between;gap:10px 16px;padding-bottom:12px;
  border-bottom:1px solid var(--line)}

/* ---- the card's name ----
   THE BAND'S OWN DEVICE, the same one Book Us uses: a Royal Red strip of white
   Bold text, sentence case, as wide as its words. It is lifted from the social
   media plan, where forty-one blocks are headed exactly like this, and the
   plan's brand note is explicit — Royal Red #A50E0E for on-page elements,
   badges, boxes and rules, "since none sit on a coloured background". Heritage
   Scarlet leads whole surfaces; Royal Red does the small furniture on white.
   White on royal is 7.87:1.

   It replaces the admin's 12px scarlet label, which was too quiet to hold a card
   together — beside a row of 44px tabs it read as a caption for the tabs rather
   than as the name of the thing. Set at 17px rather than Book Us's 20: this one
   shares its line, and the strip has to sit inside a card rather than head a
   section of the page.

   The inset follows the document it came from — 5px at the sides against 4px
   above and below, the fill drawn almost exactly round the words, which is the
   reverse of how a button is padded. */
.an-card-name{display:inline-block;margin:0;background:var(--royal);color:#fff;
  font-weight:700;font-size:17px;line-height:1.2;letter-spacing:.01em;
  text-transform:none;padding:4px 7px}
/* A card's note explains the list under it and must not compete with it. At
   body size — which is what it inherited — three lines of explanation were
   taller and louder than the five rows they were explaining. */
.an-card .hint{margin:12px 0 0;font-size:13.5px;line-height:1.5;max-width:56ch}
.an-card .an-when{font-size:15.5px;margin-top:12px;max-width:46ch}

/* They assemble in the order they are read rather than landing in one frame.
   Written here rather than counted out in the admin: there are four cards, or
   five when the site has had a wrong address asked for, and a stylesheet can
   count that far by itself. */
.an-cards>.an-card:nth-child(2){--in:70ms}
.an-cards>.an-card:nth-child(3){--in:140ms}
.an-cards>.an-card:nth-child(4){--in:210ms}
.an-cards>.an-card:nth-child(n+5){--in:280ms}

.an-subtabs{display:flex;flex-wrap:wrap;gap:4px}
/* 44px, like every other target on this site — the menu rows, the roster jump
   links, the quote dots and the ticket steppers are all 44 and tests/test-mobile
   holds them there. A tab is a thing pressed with a thumb on a phone. */
.an-subtab{font:inherit;font-weight:700;font-size:12.5px;letter-spacing:.09em;
  text-transform:uppercase;min-height:44px;padding:0 13px;cursor:pointer;
  background:none;border:1px solid var(--line);color:var(--mute);
  transition:border-color .16s,color .16s,background .16s}
/* An ink OUTLINE on hover, not an ink fill and not a second red: royal is
   spoken for on this screen — it is what the card names are set in — and a
   hovered tab filled with it would read as a second heading. */
.an-subtab:hover{border-color:var(--ink);color:var(--ink)}
.an-subtab.on{background:var(--scarlet);border-color:var(--scarlet);color:#fff}
.an-subtab:focus-visible{outline:3px solid var(--scarlet);outline-offset:2px}

/* The face that is showing arrives rather than appearing. Nothing animates on
   the way out — you watch something open, you do not watch it shut. */
.an-panel:not([hidden]){
  animation:ad-unfold var(--ad-quick,.18s) var(--ad-ease,ease) backwards}

/* Five rows, and the rest behind one press. The twentieth most-read page is a
   real answer to a real question, so it is one press away rather than gone. */
.an-rank.folded>li:nth-child(n+6){display:none}
.an-more{margin:8px 0 0;font:inherit;font-weight:700;font-size:12.5px;
  letter-spacing:.09em;text-transform:uppercase;color:var(--scarlet);
  background:none;border:0;padding:0;cursor:pointer;min-height:44px;
  display:inline-flex;align-items:center}
.an-more:hover{color:var(--royal)}
.an-more:focus-visible{outline:3px solid var(--scarlet);outline-offset:2px}

/* ---- the clock ----
   Twenty-four bars in a row, midnight to midnight. The same device as the
   thirty-day chart and deliberately so: two charts on one screen that behave
   differently are two things to learn. */
.an-clock{display:flex;align-items:flex-end;gap:2px;height:86px;
  margin:14px 0 0;border-bottom:2px solid var(--line)}
.an-hr{flex:1 1 0;display:flex;align-items:flex-end;height:100%;min-width:0}
/* SCARLET, LIKE EVERY OTHER BAR ON THE SCREEN. The clock used to be drawn in
   ink while the chart above it and the ranked lists beside it were scarlet —
   and now that the hour of the day and the day of the week are two faces of one
   card, turning the card changed the colour of its bars for no reason a reader
   could name. Scarlet leads on white; ink is what it goes to when pointed at,
   the same way round as the chart. */
.an-hr b{display:block;width:100%;min-height:1px;height:var(--h,0%);
  background:var(--soft,var(--scarlet));transform-origin:bottom;
  animation:an-grow .5s var(--ad-ease,ease) backwards;animation-delay:var(--in,0ms)}
.an-hr:hover b{background:var(--royal)}

.an-when{margin:10px 0 0;font-size:16.5px;max-width:60ch}
.an-when b{font-weight:900}

/* ---- a ranked list where the bar IS the number ----
   The eye compares lengths faster than it compares digits, and the digits are
   there anyway for anybody who wants the figure rather than the shape. */
.an-rank{list-style:none;margin:10px 0 0;padding:0;display:grid;gap:7px}
.an-rank li{display:grid;grid-template-columns:minmax(0,15em) minmax(40px,1fr) auto;
  align-items:center;gap:12px;font-size:14px}
.an-rank-name{overflow-wrap:anywhere}
.an-rank-bar{height:10px;background:var(--line)}
.an-rank-bar b{display:block;height:100%;background:var(--soft,var(--scarlet));
  transform-origin:left;animation:an-fill .55s var(--ad-ease,ease) backwards;
  animation-delay:var(--in,0ms)}
.an-rank-n{font-weight:700;text-align:right;min-width:3.5em;
  font-variant-numeric:tabular-nums}

/* A ranked row that can narrow the screen is a button filling its own row, so
   the whole line is the target rather than the words in it.

   THE ROW ITSELF STOPS BEING A GRID WHEN IT HOLDS ONE. It did not, and the
   result was two grids fighting: the button was laid into the row's first
   column — thirteen ems at most, and free to collapse — so the name got 71
   pixels and the bar 40, and "/index.html" wrapped as "/index.ht ml" on every
   list that could be pressed. Measured, not guessed: the wide lists that could
   not be pressed were drawing their names at 196px and their bars at 863. */
.an-rank.can-pick li{display:block;padding:0}
.an-rank.can-pick button{display:grid;
  grid-template-columns:minmax(0,15em) minmax(40px,1fr) auto;
  align-items:center;gap:12px;width:100%;min-height:44px;padding:2px 6px;
  margin:0 -6px;font:inherit;font-size:14px;text-align:left;cursor:pointer;
  background:none;border:0;color:inherit;transition:background .14s}
.an-rank.can-pick button:hover{background:var(--tint)}
.an-rank.can-pick button:hover .an-rank-bar b{background:var(--royal)}
.an-rank.can-pick button:focus-visible{outline:3px solid var(--scarlet);
  outline-offset:-1px}

@media(max-width:600px){
  /* The name over its own bar rather than three columns squeezed into a phone,
     where the middle one would be about thirty pixels of nothing. */
  .an-rank li,.an-rank.can-pick button{grid-template-columns:1fr auto;
    gap:4px 12px}
  .an-rank-name{grid-column:1}
  .an-rank-n{grid-column:2;grid-row:1}
  .an-rank-bar{grid-column:1/-1}
}

/* ---- how much the site is read ----
   Thirty bars, drawn with heights and nothing else. A charting library would be
   more code than the whole admin to draw a list with heights, and every one of
   them would bring its own colours, its own typeface and its own idea of a
   tooltip into a page built to avoid exactly that. */
.rd-chart{display:flex;align-items:flex-end;gap:3px;height:170px;
  margin:6px 0 0;padding:14px 0 0;border-bottom:2px solid var(--line)}
.rd-bar{flex:1 1 0;display:flex;align-items:flex-end;height:100%;min-width:0}
/* A quiet day is a bar of no height, which reads as missing data rather than as
   a day nobody came. One pixel says "counted, and it was none". */
.rd-bar{position:relative}
/* THEY GROW, LEFT TO RIGHT, and the stagger is capped in admin.js rather than
   proportional: thirty bars fourteen milliseconds apart is a sweep, and three
   hundred at the same spacing is four seconds of watching a chart assemble
   itself, which is a chart nobody can read yet. */
.rd-bar b{display:block;width:100%;min-height:1px;height:var(--h,0%);
  background:var(--scarlet);transform-origin:bottom;
  animation:an-grow .5s var(--ad-ease,ease) backwards;animation-delay:var(--in,0ms)}
.rd-bar:hover b{background:var(--royal)}
/* WHERE THE SAME POSITION IN THE STRETCH BEFORE SAT — a mark across the bar
   rather than a second bar beside it. Two sets of bars at this width become one
   comb and get read as a single series; a level line is the shape of a target
   marker, which people already know how to read. */
.rd-bar i{position:absolute;left:0;right:0;bottom:var(--w,0%);height:0;
  border-top:1px dashed var(--mute);opacity:.75;pointer-events:none}

.rd-axis{display:flex;justify-content:space-between;margin:6px 0 0;
  font-size:12px;font-weight:700;letter-spacing:.06em;color:var(--mute)}

@keyframes an-grow{from{transform:scaleY(.001)}}
@keyframes an-fill{from{transform:scaleX(0)}}
@keyframes an-draw{to{stroke-dashoffset:0}}
@keyframes an-fade{from{opacity:0}}

/* MOVEMENT IS DECORATION AND IT IS THE FIRST THING TO GO. Everything above
   still arrives, still says the same thing and still holds the same figure —
   it simply arrives already there. Note the line: taking only the animation off
   would leave it holding its opening frame, which is a chart with no line in
   it, so the dash it was drawn with is put back as well. */
@media(prefers-reduced-motion:reduce){
  .an-card,.an-panel:not([hidden]),.rd-bar b,.an-hr b,.an-rank-bar b,
  .an-line-fill,.an-line-was{animation:none}
  .an-line-path{animation:none;stroke-dasharray:none;stroke-dashoffset:0}
  .an-big,.an-big::before,.an-chip,.an-when-btn,.an-subtab,
  .an-rank.can-pick button{transition:none}
  button.an-big:hover{transform:none}
}

.ad-note.warn{border-left:4px solid var(--gold);background:var(--tint);
  padding:14px 16px}
.ad-note-form{display:flex;flex-wrap:wrap;gap:8px;margin-top:10px}
.ad-note-form input{flex:1 1 220px;min-height:44px;padding:0 12px;font:inherit;
  border:1px solid var(--line);background:#fff;color:var(--ink)}

/* ---- the welcome ----
   Ink, the crest, a gold rule and the time of day. Square, like everything else.
   It covers the admin for under two seconds and takes any key or any click as
   "yes, thank you, I know who I am".

   THE TYPE IS THE SITE'S, NOT A COPY OF IT. The greeting is the kicker and the
   name is a heading — both declared once, up with the rest of the type, and
   only their colour changed here. Writing the sizes and the tracking out again
   is how a first version ended up setting the name in Title Case with negative
   letter-spacing, which is not how this band sets a heading anywhere else. */
/* THE COVER, put up in the head before the body has painted. It is a rule in
   the stylesheet rather than an element, because an element cannot exist until
   there is a body to put it in — and by then the page has painted, which is the
   flicker this removes. A ::before on the root paints as soon as this file is
   parsed, which is in the head. */
/* PAINTED OVER, NOT TAKEN AWAY. While the server is being asked whether
   somebody is signed in, the door used to be display:none for anybody who was
   signed in last time — which is exactly the person whose password manager has
   something to offer, and a form that is not in the layout is a form no manager
   can see. It is drawn, full size and opaque, with a sheet of ink over the page
   for the fifth of a second the asking takes.

   The same ink as the welcome's own cover, at the same depth, so the two are
   indistinguishable to anybody looking at the screen. */
html.ad-asking::before{content:'';position:fixed;inset:0;z-index:199;
  background:var(--ink)}

html.pre-welcome::before{content:'';position:fixed;inset:0;z-index:199;
  background:var(--ink)}

/* No fade-in on the overlay itself: it arrives on top of a screen that is
   already ink, so fading it in would only delay the crest. The crest, the rule
   and the name have their own entrances and those are the ones worth seeing. */
/* Carries `mark dark` as well, which is where the crest in the corner comes
   from — the site's own watermark rule, not a second one written here. That
   rule sets position:relative; this one is later in the file and at the same
   specificity, so fixed wins. Its overflow:hidden is wanted, and its
   `.mark>*{z-index:1}` is what keeps the crest and the name in front of it. */
.ad-welcome{position:fixed;inset:0;z-index:200;display:grid;place-items:center;
  background:var(--ink);cursor:pointer}

/* The watermark arrives on its own, a beat before the crest, and slowly. It is
   the room the greeting happens in rather than part of the greeting, and
   something that large snapping into place would read as a mistake. */
.ad-welcome::before{animation:ad-wel-mark 1.5s ease both}
.ad-welcome.going{animation:ad-wel-out .5s ease both}
.ad-welcome-in{display:flex;flex-direction:column;align-items:center;
  text-align:center;padding:24px;max-width:min(92vw,760px)}

/* The crest is the point of the screen, so it is given the room to be one.
   Held back from the full width on a phone, where the name underneath needs
   somewhere to go. */
.ad-welcome img{width:clamp(112px,24vw,176px);height:auto;
  animation:ad-wel-crest .78s cubic-bezier(.2,.7,.3,1) both}

/* Drawn from the middle outwards, and sized against the crest above it rather
   than at a number that happens to look right at one width.

   SIX PIXELS IS THE BAND'S BAR, not a thickness chosen by eye. It is the same
   --bar:6px the gold rule under every heading on this site uses; at three it
   was half the brand's own weight and read as a hairline beside a 176px crest.
   Equal space above and below, because here it divides two things rather than
   underlining one — the heading rule's "gap equals thickness" belongs to a bar
   that hugs the word above it, and this one hugs nothing. */
.ad-welcome-rule{display:block;height:6px;width:clamp(150px,32vw,232px);
  background:var(--gold);margin:26px 0;transform:scaleX(0);
  animation:ad-wel-rule .62s .38s cubic-bezier(.2,.7,.3,1) both}

/* The kicker's weight, tracking and casing come from .kicker, up with the rest
   of the type. Only the size is set here, and only because 12px is measured
   against a 48px heading in a column of text — beside a name at 84px on a
   screen with nothing else on it, it disappears. Scaled, not redesigned. */
.ad-welcome-hi{color:var(--gold);margin:0;font-size:clamp(15px,2.4vw,22px);
  font-weight:900;text-transform:uppercase;letter-spacing:.14em;
  animation:ad-wel-up .58s .58s ease both}
.ad-welcome-who{color:#fff;margin:10px 0 0;line-height:1.02;
  animation:ad-wel-up .58s .74s ease both}

@keyframes ad-wel-out{to{opacity:0;visibility:hidden}}
@keyframes ad-wel-crest{from{opacity:0;transform:translateY(14px) scale(.86)}
  to{opacity:1;transform:none}}
@keyframes ad-wel-mark{from{opacity:0}to{opacity:1}}
@keyframes ad-wel-rule{to{transform:scaleX(1)}}
@keyframes ad-wel-up{from{opacity:0;transform:translateY(10px)}to{opacity:1;transform:none}}

/* Asked for reduced motion, it never runs at all — admin.js returns before
   drawing it. This is here for the case where the setting changes mid-session
   with the overlay already on screen: no movement, and it still goes away. */
@media(prefers-reduced-motion:reduce){
  .ad-welcome,.ad-welcome *{animation:none !important}
}

.ad-bar{display:flex;flex-wrap:wrap;align-items:center;gap:12px;
  margin:0 0 4px;padding-bottom:14px}
.ad-tally{margin:0;font-size:13.5px;color:var(--mute)}
.ad-tally b{color:var(--ink);font-size:14px}
.ad-find{flex:1 1 200px;min-width:0;display:block}
.ad-find input{width:100%;min-height:44px;padding:0 14px;font:inherit;
  font-size:15px;background:#fff;color:var(--ink);border:1px solid var(--line)}
.ad-find input:focus{outline:3px solid var(--gold);outline-offset:1px;
  border-color:var(--ink)}
.btn-sm{min-height:44px;padding:0 16px;font-size:12px}

.ad-list{border-top:1px solid var(--line)}
.ad-entry{border-bottom:1px solid var(--line)}
/* Gone by, but not gone. A past concert is still edited from here — it holds
   the photographs and the result — so it is quietened rather than hidden. */
.ad-entry.past .ad-head{opacity:.62}
.ad-entry.past .ad-head:hover{opacity:1}

/* The heading IS the control — an entry is opened by pressing its name, not by
   finding a small arrow at one end. */
.ad-head{width:100%;display:flex;align-items:center;gap:14px;
  min-height:64px;padding:12px 38px 12px 0;position:relative;
  background:none;border:0;cursor:pointer;text-align:left;font:inherit;
  color:inherit}
.ad-head:hover{background:var(--tint)}
.ad-head-text{flex:1 1 auto;min-width:0;display:flex;flex-direction:column;gap:2px}
.ad-name{font-weight:700;font-size:16px}
.ad-name em{color:var(--mute);font-style:italic;font-weight:500}
.ad-sub-text{font-size:13.5px;color:var(--mute);
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}

/* ---- the date, as a date ----
   A block the eye can run down, rather than "2026-08-22" buried in a line of
   prose. The full form sits beside it on a wide screen, because the day of the
   week is the thing you are actually checking and the block has no room for it. */
.ad-stamp{flex:0 0 auto;display:grid;place-items:center;align-content:center;
  width:58px;padding:7px 0;background:var(--scarlet);color:#fff;
  border-radius:0;line-height:1.1}
.ad-stamp b{font-size:21px;font-weight:900;letter-spacing:-.02em}
.ad-stamp i{font-style:normal;font-size:11.5px;font-weight:900;
  letter-spacing:.14em;text-transform:uppercase}
.ad-stamp u{text-decoration:none;font-size:10px;color:rgba(255,255,255,.72);
  letter-spacing:.06em}
.ad-stamp.past{background:var(--mute)}
.ad-stamp-none{width:58px;text-align:center;color:var(--line);font-size:20px}
.ad-when{flex:0 0 auto;width:118px;font-size:13px;color:var(--mute)}
@media(max-width:820px){.ad-when{display:none}}

/* ---- a face ----
   A missing photograph becomes an initial rather than a broken-image mark,
   which is what a roster half filled in actually looks like. */
.ad-face{flex:0 0 auto;width:46px;height:46px;border-radius:0;
  object-fit:cover;background:var(--line)}
.ad-face-none{display:grid;place-items:center;background:var(--tint);
  border:1px dashed var(--line);color:var(--mute);
  font-weight:900;font-size:16px}

/* ---- chips ----
   Only ever things worth acting on: what is missing, what is unusual. A chip on
   every row would be a column, and a column nobody reads. */
.ad-chips{flex:0 0 auto;display:flex;flex-wrap:wrap;gap:5px;justify-content:flex-end;
  max-width:210px}
.ad-chip{font-size:11.5px;font-weight:900;letter-spacing:.14em;
  text-transform:uppercase;padding:4px 8px;border-radius:0;
  background:var(--tint);color:var(--mute);border:1px solid var(--line)}
.ad-chip-gold{background:var(--gold);color:var(--ink);border-color:var(--gold)}
.ad-chip-ink{background:var(--ink);color:#fff;border-color:var(--ink)}
.ad-chip-scarlet{background:var(--scarlet);color:#fff;border-color:var(--scarlet)}

.ad-head::after{content:'';position:absolute;right:12px;top:50%;
  width:9px;height:9px;margin-top:-6px;
  border-right:2px solid var(--scarlet);border-bottom:2px solid var(--scarlet);
  transform:rotate(45deg);transition:transform .2s ease}
.ad-head[aria-expanded=false]::after{transform:rotate(-45deg)}
/* A ROW THAT OPENS A CARD POINTS ALONG, NOT DOWN. The arrow says where the
   thing is about to appear, and a chevron pointing down at a row that no longer
   unfolds is the page telling a small lie about itself.

   The nudge on hover is written translate-then-rotate, in that order: after a
   rotation the axes have turned with it, and translateX would send the arrow
   diagonally. */
.ad-head[data-card]::after{transform:rotate(-45deg);margin-top:-5px}
.ad-head[data-card]:hover::after{transform:translateX(3px) rotate(-45deg)}
@media(prefers-reduced-motion:reduce){.ad-head::after{transition:none}}

/* A phone is where a photograph actually is, so this is the layout that
   matters most, not a fallback. Side by side leaves the button squeezed into
   about 90px; stacked it is a full-width target. */
@media(max-width:600px){
  .ad-photo{flex-direction:column;gap:10px}
  .ad-photo-tile{width:100%;max-width:260px;height:auto;aspect-ratio:4/3}
  .ad-pick span{width:100%;justify-content:center}

  /* THE DIFF TABLE STOPS BEING A TABLE.
     Three columns at 40/30/30 of about 330px is 132px for a field name and
     99px each for the old and new values — where the names are things like
     "Committee & staff — Andrew Rigby — role" and the values are sentences.
     Every cell wraps to four or five lines and the row becomes unreadable.

     Stacked, each row is the field name and then two labelled lines. The
     labels are added here rather than in the markup because they are only
     meaningful in this layout: with columns, the headings say it already. */
  .ad-diff,.ad-diff tbody,.ad-diff tr,.ad-diff th,.ad-diff td{
    display:block;width:auto}
  .ad-diff tr{padding:12px 0}
  .ad-diff tr+tr{border-top:1px solid var(--line)}
  .ad-diff tr+tr th,.ad-diff tr+tr td{border-top:0}
  .ad-diff th{padding:0 0 7px}
  .ad-diff td{padding:2px 0 2px 52px;position:relative;min-height:20px}
  .ad-diff td::before{position:absolute;left:0;top:3px;width:46px;
    font-size:11.5px;font-weight:900;letter-spacing:.14em;text-transform:uppercase;
    color:var(--mute)}
  .ad-diff .was::before{content:"Was"}
  .ad-diff .now::before{content:"Now"}

  .ad-head{gap:11px;padding-right:30px}
  .ad-stamp,.ad-stamp-none{width:48px}
  .ad-stamp b{font-size:18px}
  .ad-face{width:40px;height:40px}
  /* Chips drop below the name rather than squeezing it to nothing. */
  .ad-head{flex-wrap:wrap}
  .ad-chips{max-width:none;justify-content:flex-start;width:100%;padding-left:59px}
}

.ad-body{padding:6px 0 26px;display:grid;gap:18px}
.ad-sub{margin:14px 0 0;font-size:11.5px;font-weight:900;letter-spacing:.14em;
  text-transform:uppercase;color:var(--scarlet)}

/* ---- one field ---- */
.ad-field{display:grid;gap:7px}
/* A GROUP OF BUTTONS HAS NO SINGLE CONTROL TO POINT A <label> AT, so its label
   is a span that the group names as its own — and it has to look like every
   other label on the form, which it did not: "What kind needed" came out in
   sentence case beside eleven small capitals. */
.ad-field label,.ad-field .ad-field-label{display:block;font-weight:900;
  font-size:11.5px;letter-spacing:.14em;text-transform:uppercase;color:var(--mute)}
.ad-field label em,.ad-field .ad-field-label em{font-style:normal;
  color:var(--scarlet);letter-spacing:0;text-transform:none;font-size:11.5px}
.ad-field input,.ad-field select,.ad-field textarea{
  /* THE WEIGHT AS WELL AS THE FAMILY. A form control does not inherit either:
     the family was asked for and the weight was not, so every box in the admin
     was drawing its text at 400 — a weight this site does not own and the
     browser makes up — while everything around it was Medium. It showed up as
     the grey suggestion behind the caret being visibly heavier than the words
     typed over it. */
  font-family:inherit;font-weight:inherit;font-size:16px;padding:13px 15px;
  border:2px solid var(--line);border-radius:0;background:#fff;color:var(--ink);
  width:100%;min-height:48px}
/* 16px is not a style choice. Below it, iOS zooms the page in when a field is
   focused and does not zoom back out, which leaves somebody stranded at 150%
   halfway through a form. */
.ad-field textarea{line-height:1.5;resize:vertical}
/* ---- the dots in a password box --------------------------------------------
   THE MASK IS A GLYPH LIKE ANY OTHER, and it comes from whatever face the box
   is set in. Noverion's is a small middot sitting low on the line, so a typed
   password looked like a row of full stops — smaller than the address in the
   box above it and nothing like the dots anybody expects.

   So password boxes, and only password boxes, are set in a face whose bullet is
   a bullet. Nobody reads prose in one: what matters is that a dot looks like a
   dot and that they are far enough apart to be counted. */
/* AND SMALLER THAN THE WORDS AROUND THEM. A bullet in a face that has one is
   drawn at about a third of its type size, where a middot is a tenth of it — so
   the same box that was showing full stops showed something closer to buttons.
   Four fifths of the size, which puts a dot at 3.5px against the 5px it was and
   the 1.5px it started at.

   Written for all three places a password box appears, because the boxes on the
   sign-in card and in the admin's own form both carry sizes of their own that
   would otherwise win. */
/* ---- what the browser fills in ---------------------------------------------
   A remembered address arrives in Chrome's own pale mint, which on a white card
   looks like a box that has gone transparent and let the photograph through.
   The colour cannot be set directly — it is painted over the box — so the box
   is filled with an inset shadow instead, which is the way round everybody uses
   because it is the only one that works. */
input:-webkit-autofill,
input:-webkit-autofill:hover,
input:-webkit-autofill:focus{
  -webkit-text-fill-color:var(--ink);
  -webkit-box-shadow:0 0 0 40px #fff inset;
  box-shadow:0 0 0 40px #fff inset;
  /* Long enough that it never actually arrives: the animation is only there to
     keep the shadow from being repainted away. */
  transition:background-color 9999s ease-in-out 0s}

input[type=password],
.ad-field input[type=password],
.ad-gate-card .form input[type=password]{
  font-family:Verdana,Tahoma,'DejaVu Sans',sans-serif;
  font-size:.8em;letter-spacing:.14em}

/* ---- SHOWING A PASSWORD ---------------------------------------------------
   Behind a row of dots a mistyped password and a wrong one look the same, and
   the sentence you get back for them is the same too. So the box can be opened.

   The button sits inside the right-hand end of the box rather than beside it:
   beside it, the box gets shorter and every other box on the form is suddenly
   a different width. It is the site's own pressable capitals, in scarlet,
   which is what everything you can press in here is.

   The face changes with the state, and deliberately: the dots need the
   letter-spacing to read as dots rather than as a smudge, and letters do not —
   spaced-out letters would be the harder thing to check, which is the whole
   point of pressing it. */
.pw-box{position:relative;display:block}
.pw-box input{width:100%;padding-right:74px}
.pw-see{position:absolute;top:0;right:0;height:100%;padding:0 13px;
  background:none;border:0;cursor:pointer;
  font:inherit;font-weight:700;font-size:12.5px;letter-spacing:.09em;
  text-transform:uppercase;color:var(--scarlet);transition:color .15s}
.pw-see:hover{color:var(--royal)}
.pw-see:focus-visible{outline:3px solid var(--gold);outline-offset:-3px}
.pw-box input[type=text]{font-family:inherit;font-size:1em;letter-spacing:0}

.ad-field input:focus,.ad-field select:focus,.ad-field textarea:focus{
  border-color:var(--gold);outline:none}
/* ---- the help under a field -----------------------------------------------
   THERE WHILE IT IS NEEDED. A sentence under every field all the time turns a
   form of eleven fields into two hundred words about things the reader already
   knows — and the sentences are worth having, because they are read once, by
   whoever is filling that field in for the first time.

   So: shown while the field is empty, shown while somebody is in it, and quiet
   the moment it has an answer. Nothing is hidden that has not been answered. */
.ad-field .hint{margin:0;font-size:13px;line-height:1.45;color:var(--mute)}
.ad-card-fields .ad-field.is-answered .hint{display:none}
.ad-card-fields .ad-field.is-answered:focus-within .hint{display:block}

.ad-field-tick{gap:4px}
.ad-tick{display:flex;align-items:center;gap:11px;min-height:44px;
  cursor:pointer;font-weight:700;font-size:15px;letter-spacing:0;
  text-transform:none;color:var(--ink)}
.ad-tick input{width:22px;height:22px;min-height:0;accent-color:var(--scarlet);
  flex:0 0 auto;padding:0}

/* A picture is shown, not described. Nobody can tell from a web address whether
   it is the right photograph. */
/* A photograph, and the one control that changes it, side by side. Stacked on a
   phone — see the phone block at the foot of this file. Square, like everything
   else here. */
/* =============================================================================
   THE DOOR
   =============================================================================
   A BAND PHOTOGRAPH, DARKENED, WITH THE FORM ON TOP. It was a white page with
   SIGN IN set enormous across it and four paragraphs underneath — the shape of
   a form rather than the shape of a door, and the first thing anybody in the
   band sees of the admin.

   The photograph is the one the site already falls back to on the homepage,
   handed over by site.js. Under it, ink and the crest, so a picture that never
   arrives leaves something deliberate rather than a hole. */
.ad-gate{position:relative;isolation:isolate;
  min-height:min(760px,78dvh);display:flex;align-items:center;
  padding:56px 24px;background:var(--ink)}
.ad-gate-art{position:absolute;inset:0;z-index:-1;
  background:var(--ink) center/cover no-repeat;
  animation:ad-gate-rise 1.1s var(--ad-ease,ease) both}

/* ---- THE CREST IS IN THE CARD ---------------------------------------------
   NOT OVER THE PHOTOGRAPH. It sat at the bottom-left of the picture with the
   footer's at the bottom-left immediately beneath it — two of them in a
   vertical line down the same edge, which is what the rule about using it
   sparingly and never on adjacent sections is there to stop.

   In the card it is the same watermark the walkthrough cards carry: pale, on
   white, bleeding off the bottom-left corner, with the form standing over it.
   The footer's is a long way below and in another colour altogether, so the two
   never read as a pair. */
.ad-gate-card{position:relative;overflow:hidden}
.ad-gate-card > *{position:relative;z-index:1}
.ad-gate-card::before{content:'';position:absolute;z-index:0;inset:0;
  pointer-events:none;
  /* As tall as the card and anchored to its foot, so the point of the crown
     meets the top edge — the size the crest is always drawn at here. */
  background:url('../img/gus-crest-light.png') left bottom/auto 100% no-repeat}
/* The scrim is heavier at the edges than in the middle, so the photograph is
   still a photograph where nothing is written over it. */
.ad-gate-art::after{content:'';position:absolute;inset:0;
  background:linear-gradient(90deg,rgba(20,16,15,.94) 0%,rgba(20,16,15,.80) 44%,
                                   rgba(20,16,15,.62) 100%)}
@media(max-width:820px){
  .ad-gate-art::after{background:rgba(20,16,15,.86)}
}
@keyframes ad-gate-rise{from{opacity:0;transform:scale(1.06)}}

/* THE TWO COLUMNS START LEVEL. Centred against each other, the words on the
   left floated somewhere in the middle of a card half again as tall, which
   reads as two things that happen to be near each other rather than as one
   page. Level tops give them an edge in common, and the kicker lands on the
   same line as the heading on the card. */
.ad-gate-in{position:relative;width:100%;max-width:var(--wrap);margin:0 auto;
  display:grid;gap:34px 56px;align-items:start;
  grid-template-columns:minmax(0,1fr) minmax(0,470px)}
/* The kicker sits on its own line above ADMIN and the card's heading does not,
   so a little off the top of the left column puts the two headings level. */
@media(min-width:901px){ .ad-gate-say{padding-top:26px} }
@media(max-width:900px){
  .ad-gate-in{grid-template-columns:minmax(0,1fr);gap:26px}
}

.ad-gate-say{color:#fff}
.ad-gate-say .kicker{color:var(--gold);margin-bottom:10px}
.ad-gate-big{font-size:clamp(54px,8vw,104px);line-height:.94;
  text-transform:uppercase;letter-spacing:.005em;color:#fff}
/* A bar in proportion to the words above it — the same 10px the hero on the
   homepage uses, at the same size of type.

   AND THE GAP ABOVE IT EQUALS ITS OWN THICKNESS, which is the brand rule and
   is what the correction below is for: it takes out the dead space every line
   box carries under the cap baseline. The site's 0.19em is measured against the
   line-height its headings use; this one is set tighter, at .94, so the same
   correction overshot and left the bar a pixel off the letters. Measured: 1px
   of gap under a 6px bar. 0.141em puts the gap back to the thickness, and both
   scale with the type, so it holds all the way down the clamp. */
.ad-gate-big.rule::after{--bar:10px;margin-top:calc(var(--bar) - 0.141em)}
/* :not(.kicker), for the second time in this stylesheet — a kicker is a <p>,
   and a rule written for "the sentence under the heading" catches it on the way
   past. Here it took the size off it and then hid it altogether on a phone. */
.ad-gate-say p:not(.kicker){margin:26px 0 0;max-width:34ch;font-size:17px;
  color:rgba(255,255,255,.82)}
@media(max-width:900px){.ad-gate-say p:not(.kicker){display:none}}

/* The form is a white card standing on the photograph — the same white the
   admin's own cards are, so signing in and using it are the same place. */
.ad-gate-card{background:#fff;padding:36px 36px 30px;
  box-shadow:0 28px 70px rgba(20,16,15,.45)}
/* The picture is what fills the door when there is one; when there is not, the
   ink and the words are the page and the card is the only thing on it. */
/* SIGN IN carries the same bar as everything else this site calls a heading —
   4px of it, in proportion to 40px of type, and it draws itself from the left
   when the card arrives. */
.ad-gate-h{font-size:40px;line-height:1;text-transform:uppercase;
  letter-spacing:.01em;margin:0 0 26px}
.ad-gate-h.rule::after{--bar:4px;margin-top:calc(var(--bar) - 0.155em)}

/* The card itself arrives a beat after the words on the left, rising and
   settling on the same curve everything else on this site moves with.

   IT RISES, IT DOES NOT FADE, and that is not a taste decision. The fade began
   at opacity 0 and, with the delay, left every field in this card completely
   transparent for the first fifth of a second and not solid until nearly a
   second in. A password manager looks for a sign-in form when the page
   arrives, and the commonest test for "can this be filled" is whether the
   field can be seen — a transparent box is not a box, so it found nothing
   worth offering, on a form that was otherwise correct in every particular.
   Measured, not guessed: the fields read opacity 0 at load and 0.46 at 400ms.

   The rise alone still reads as an arrival against the photograph, and the
   gold bar still draws itself across the heading inside the card. */
.ad-gate-card{animation:ad-gate-card-in .72s .22s cubic-bezier(.22,.61,.36,1) both}
@keyframes ad-gate-card-in{
  from{transform:translateY(26px) scale(.985)}
}
@media(prefers-reduced-motion:reduce){
  .ad-gate-card,.ad-gate-art{animation:none}
}
/* The boxes are bigger than the admin's own, because this is the one form
   somebody fills in standing up, on the door of a concert, in the dark. */
.ad-gate-card .form input{font-size:18px;padding:15px 16px;min-height:54px}
.ad-gate-card .btn{min-height:56px;font-size:14px}
.ad-gate-card .form{margin:0}
.ad-gate-card .btn{width:100%;justify-content:center;margin-top:4px}
.ad-gate-card .ad-stay{margin-top:18px}
.ad-gate-card .hint{margin-top:6px;font-size:13px;line-height:1.5;color:var(--mute)}
/* Quiet, under the tick: it is the way out for somebody who is stuck, not one
   of the two things this card is for. */
.ad-gate-lost{margin:16px 0 0}
.ad-gate-lost button{padding:4px 0;font:inherit;font-size:14px;background:none;
  border:0;border-bottom:2px solid var(--line);color:var(--mute);cursor:pointer;
  transition:.15s}
.ad-gate-lost button:hover{color:var(--scarlet);border-bottom-color:var(--scarlet)}
.ad-gate-lost button:focus-visible{outline:3px solid var(--scarlet);outline-offset:2px}
/* One or the other on the card, never both. */
#adminForgotForm,.ad-gate-back{display:none}
.ad-gate-card.is-lost #adminLogin,
.ad-gate-card.is-lost .ad-stay,
.ad-gate-card.is-lost .ad-gate-lost:not(.ad-gate-back){display:none}
/* GRID, NOT BLOCK. A .form is a grid, and its boxes are full width because a
   grid stretches them; showing this one as a block put the address box back to
   whatever width a browser thinks an <input> is — 275px against a button of
   398, on the same card as a sign-in box that fills it. */
.ad-gate-card.is-lost #adminForgotForm{display:grid}
.ad-gate-card.is-lost .ad-gate-back{display:block}
#adminForgotForm .ad-says{margin:10px 0 0;min-height:1.4em}
#adminForgotForm .hint{margin:0 0 16px}



/* ---- a picture is one tile ------------------------------------------------
   THE PICTURE IS THE BUTTON. It was an address box, a thumbnail, a button and a
   sentence stacked down the form — four controls for "which photograph is
   this?", with the address box first and largest although hardly anybody ever
   types one. Now it is the picture itself, which opens the machine's own file
   window when it is pressed, as everything else that takes a photograph does.

   Empty, it is a dashed frame saying what it wants. The address is put away
   behind a word, for the times somebody has a link rather than a file. */
.ad-photo{margin-top:8px;display:flex;gap:16px;align-items:flex-start;
  flex-wrap:wrap}
.ad-photo-tile{position:relative;display:block;width:168px;height:126px;
  border:2px dashed var(--line);background:var(--tint);cursor:pointer;
  transition:.15s;overflow:hidden}
.ad-photo.has-photo .ad-photo-tile{border-style:solid}
.ad-photo-tile:hover{border-color:var(--scarlet)}
.ad-photo-tile input{position:absolute;width:1px;height:1px;opacity:0;
  pointer-events:none}
.ad-photo-tile:focus-within{outline:3px solid var(--scarlet);outline-offset:2px}
.ad-thumb{display:block;width:100%;height:100%}
.ad-thumb img{width:100%;height:100%;object-fit:cover;display:block}

/* The word sits under the picture when there is one, and in the middle of the
   frame when there is not. */
.ad-photo-word{position:absolute;left:0;right:0;bottom:0;padding:8px 10px;
  font-weight:900;font-size:11.5px;letter-spacing:.14em;text-transform:uppercase;
  text-align:center;color:var(--mute)}
.ad-photo.has-photo .ad-photo-word{color:#fff;
  background:linear-gradient(180deg,rgba(20,16,15,0),rgba(20,16,15,.72))}
.ad-photo:not(.has-photo) .ad-photo-word{top:0;display:flex;
  align-items:center;justify-content:center}

.ad-photo-side{flex:1 1 220px;display:grid;gap:8px;align-content:start;
  padding-top:2px}
.ad-photo-acts{display:flex;flex-wrap:wrap;gap:6px 16px;margin:0}
.ad-photo-acts button{padding:4px 0;font:inherit;font-size:13.5px;
  background:none;border:0;border-bottom:2px solid var(--line);
  color:var(--mute);cursor:pointer;transition:.15s}
.ad-photo-acts button:hover{color:var(--scarlet);border-bottom-color:var(--scarlet)}
.ad-photo-acts button:focus-visible{outline:3px solid var(--scarlet);
  outline-offset:2px}
.ad-photo-box{display:block}


/* The file input itself is never shown — every browser draws it differently and
   none of them draw it like this site. The label is the button, which is why it
   carries the focus ring rather than the input. */
.ad-pick{display:inline-block}
.ad-pick input{position:absolute;width:1px;height:1px;opacity:0;
  overflow:hidden;clip:rect(0 0 0 0)}
.ad-pick span{display:inline-flex;align-items:center;min-height:44px;
  padding:0 16px;cursor:pointer;font:inherit;font-weight:700;font-size:14px;
  border:2px solid var(--ink);background:#fff;color:var(--ink)}
.ad-pick span:hover{background:var(--ink);color:#fff}
.ad-pick input:focus-visible + span{outline:3px solid var(--scarlet);
  outline-offset:2px}

.ad-photo-say{margin:0;font-size:13px;color:var(--mute);min-height:1.2em}

/* Putting the website back. Set apart from the table of what changed, and
   below it, because it does more than that table describes — it replaces
   everything, and somebody who has just read three rows should not meet this
   as though it undid only those three. */
.ad-undo{margin-top:18px;padding-top:16px;border-top:2px solid var(--line)}
.ad-undo-go{font:inherit;font-weight:700;font-size:14px;min-height:44px;
  padding:0 16px;cursor:pointer;border:2px solid var(--scarlet);
  background:#fff;color:var(--scarlet)}
.ad-undo-go:hover{background:var(--scarlet);color:#fff}
.ad-undo-go[disabled]{opacity:.6;cursor:default}
.ad-undo .hint{margin-top:8px}
/* Long label, deliberately — it says what it does rather than "Undo", which
   would be shorter and would not warn anybody. So it wraps and grows instead of
   staying one line and running off the side. */
.ad-undo-go{max-width:100%;height:auto;padding:11px 16px;text-align:left;
  line-height:1.3}

/* Move and remove, at opposite ends: one is housekeeping and one is
   destruction, and they should not sit side by side where a slip does the wrong
   one. */
.ad-entry-foot{margin-top:6px;display:flex;align-items:center;
  justify-content:space-between;gap:16px}
.ad-move{display:flex;gap:6px}
.ad-move button{font:inherit;font-weight:700;font-size:12.5px;
  letter-spacing:.09em;text-transform:uppercase;min-height:44px;padding:0 12px;
  background:none;border:2px solid var(--line);color:var(--ink);cursor:pointer}
.ad-move button:hover:not([disabled]){border-color:var(--ink)}
.ad-move button[disabled]{opacity:.35;cursor:default}

/* While a search is filtering, moving a row would swap it with something not on
   screen. The buttons say so by looking unavailable; admin.js refuses in
   words. */
.ad-list.is-filtered .ad-move button{opacity:.35;cursor:default}
.ad-remove{font:inherit;font-weight:700;font-size:13px;min-height:44px;
  padding:0 2px;background:none;border:0;cursor:pointer;
  color:var(--scarlet);border-bottom:2px solid transparent}
.ad-remove:hover{border-bottom-color:var(--scarlet)}

.ad-actions{margin-top:26px}

/* Two boxes side by side where there is room, stacked where there is not. Dates
   and times, seats and prices: pairs that are read together. */
.ad-two{display:grid;grid-template-columns:1fr 1fr;gap:18px}
@media(max-width:620px){.ad-two{grid-template-columns:1fr}}

/* Something that cannot be changed is shown as text, not as a greyed-out box.
   A disabled field invites people to try. */
.tk-fixed{margin:0;font-weight:700;font-size:16px;padding:13px 0}

/* What the numbers add up to, said in a sentence — a wrong capacity is obvious
   in "30 seats at £15.00 — a full hall is £450" and invisible in a box. */
.tk-sums{background:var(--tint);border-left:4px solid var(--gold);
  padding:14px 16px;margin:4px 0}
.tk-sums p{margin:0;font-size:15px}
.tk-live{background:var(--tint);padding:14px 16px;margin:4px 0;font-size:15px}
.tk-live p{margin:0 0 6px}
.tk-live p:last-child{margin:0}
.tk-on{color:#0B6B3A}

/* ---- what happened when you saved ---- */
.ad-note{padding:15px 18px;margin:0 0 22px;font-size:15px;
  border-left:4px solid var(--line);background:var(--tint)}
.ad-note.ok{border-left-color:#0B6B3A;background:#F1F8F3}
.ad-note.bad{border-left-color:var(--scarlet);background:#FFF4F4}

/* ---------- responsive ---------- */
@media(max-width:1000px){
  .cards,.steps{grid-template-columns:1fr 1fr}
  .record{grid-template-columns:1fr 1fr}
  .split,.split-2{grid-template-columns:1fr;gap:36px}
  .players{grid-template-columns:repeat(4,1fr)}
  /* No longer a grid, so the old grid-template-columns here did nothing once
     the footer became a row. The brand block takes the full width and the three
     link columns share what is left, still evenly spaced. */
  .foot-brand{flex:1 1 100%}
  .f-col{flex:1 1 auto}
  .specs{grid-template-columns:1fr}
  .spec:nth-child(odd){padding-right:0}
  /* THE MENU STARTS WHERE THE HEADER ENDS, MEASURED
     This was inset:58px. The header is 73px, so the menu opened 15px too high
     and its first link went up behind the header. --hdr-h is the measured
     height, so the two now meet exactly however the header changes.

     It covers the page to the bottom rather than stopping partway: a press
     anywhere off the links shuts it, and there is nowhere on screen that looks
     pressable but isn't. The links sit at the top; the rest is the darkened
     page showing through.

     100dvh, not 100vh. On a phone vh is the height of the screen with the
     address bar HIDDEN, which is taller than what can actually be seen while it
     is showing — so a menu sized in vh runs off the bottom by the height of the
     bar. dvh is the space there is right now. */
  .nav{position:fixed;top:var(--hdr-h);left:0;right:0;bottom:0;
    height:calc(100dvh - var(--hdr-h));
    background:var(--ink);flex-direction:column;
    align-items:stretch;gap:0;padding:8px 24px 22px;display:none;
    border-bottom:2px solid var(--gold);
    overflow-y:auto;-webkit-overflow-scrolling:touch;overscroll-behavior:contain}
  .nav.open{display:flex}

  /* The page behind is held still while the menu is over it. A page that scrolls
     under a menu standing still reads as the menu having come adrift from the
     site. */
  html.nav-open,html.nav-open body{overflow:hidden}
  /* The dropped-down menu is a stack of rows, not a row of tabs, so the
     header-bottom trickery above is undone here. */
  .nav{align-self:auto;margin-bottom:0}
  /* 14px above and below a 13px line makes a 44px row — a target that can be hit
     with a thumb without looking. flex:0 0 auto stops the links stretching to
     share out a tall menu between them, which on a phone held sideways would
     give six links wildly different heights. */
  .nav a{padding:14px 0;border-bottom:1px solid rgba(255,255,255,.1);
    flex:0 0 auto;min-height:44px;align-items:center}
  .nav .btn{align-self:auto;margin:14px 0 0;justify-content:center;
    flex:0 0 auto;min-height:52px}
  /* In the dropped-down menu the icons stay a row, centred, under everything
     else. The hairline that divides them from the nav on a wide screen would be
     a vertical line in the middle of a stack here, so it becomes a rule across
     the top instead. Bigger targets too: this is the touch layout. */
  .social{align-self:auto;margin:20px 0 0;padding:18px 0 0;gap:8px;
    justify-content:center;
    border-left:0;border-top:1px solid rgba(255,255,255,.14)}
  .social a{width:44px;height:44px}
  .social svg{width:21px;height:21px}
  .burger{display:flex}
  .brand i{display:none}
}
@media(max-width:640px){
  body{font-size:16px}
  .sec{padding:58px 0}
  .hero-in{padding:60px 24px 74px}
  .cards,.steps{grid-template-columns:1fr}
  .players{grid-template-columns:repeat(2,1fr)}
  .roster-jump{gap:6px}
  .roster-jump a{font-size:11px;padding:8px 11px}
  /* On a phone everything stacks, so the three link columns take a full line
     each rather than being squeezed side by side. */
  .f-col{flex:1 1 100%}
  /* Nothing to add here: sizeCredit() matches the line to whatever width the
     rule has at this breakpoint, and the 12px floor in the base rule is what
     applies if the script never runs. */
  .form .row{grid-template-columns:1fr}
  .spec{grid-template-columns:1fr;gap:4px}
}
