/* Uses the same semantic palette in Day and Night. */
.notification-button{position:relative;flex:0 0 42px}.notification-button svg{width:23px;height:23px;fill:none;stroke:currentColor;stroke-width:1.8}.notification-button span:not(:empty){position:absolute;right:0;top:0;min-width:16px;border-radius:20px;padding:0 4px;font-size:10px;color:var(--primary-ink);background:var(--accent-fill)}
.add-action{width:auto;min-width:44px;padding:9px 15px;font-size:15px;border-radius:12px}.creation-tabs{margin:0 0 24px;display:grid;grid-template-columns:1fr 1fr}.creation-tabs button{min-height:46px}.caught-up{color:var(--muted);font-size:13px;margin:0 0 15px}.attention-banner{border:1px solid var(--mine-border);background:var(--accent-surface);border-radius:16px;margin:0 0 22px}.attention-link{display:flex;justify-content:space-between;align-items:center;width:100%;text-align:left;padding:16px;background:transparent;border:0;border-radius:16px;gap:12px;color:var(--text)}.attention-link small,.enquiry-card small,.venue-result small,.notification-link small{display:block;font-size:12px;color:var(--muted);margin-top:4px}.attention-link>span:last-child{white-space:nowrap;font-weight:700;color:var(--accent)}
.enquiry-card{display:block;text-align:left;width:100%;margin:0 0 12px;padding:18px;border:1px solid var(--line2);background:var(--panel);color:var(--text);border-radius:16px}.enquiry-card:hover{background:var(--hover)}.enquiry-card-head,.enquiry-card-foot{display:flex;justify-content:space-between;align-items:flex-start;gap:12px}.enquiry-card-head strong{font-size:17px}.enquiry-card-foot{margin-top:14px;font-size:12px;line-height:1.5}.enquiry-badge{display:inline-block;font-size:10px;font-weight:800;letter-spacing:.08em;border:1px solid var(--info);color:var(--info);padding:4px 7px;border-radius:6px;white-space:nowrap}.deadline-row{display:flex;flex-wrap:wrap;gap:8px;margin:12px 0 0}.deadline{font-size:12px;color:var(--muted)}.deadline.due{color:var(--warn);font-weight:600}.enquiry-date{padding:18px 0;border-top:1px solid var(--line)}.enquiry-date-head{display:flex;flex-wrap:wrap;gap:8px;align-items:center;justify-content:space-between}.enquiry-date h3{font-size:16px;margin:0}.enquiry-date-summary{font-size:11px;white-space:normal;color:var(--muted)}.enquiry-date-summary.bad{color:var(--bad)}.enquiry-date-summary.good{color:var(--good)}.enquiry-date-summary.wait{color:var(--warn)}.enquiry-date-summary.dep{color:var(--warn)}.enquiry-date-summary.cover{color:var(--cover)}.enquiry-own-row{display:flex;align-items:center;gap:9px;font-size:12px;margin:14px 0 8px}.enquiry-own-row img{border-radius:50%;background:var(--avatar-base);object-fit:cover}.available-after{display:flex;align-items:center;gap:12px;margin:10px 0}.available-after label{font-size:12px;margin:0;flex:1}.available-after input{max-width:140px;min-width:0}.enquiry-save-state{font-size:12px;color:var(--muted);margin:8px 0 0;min-height:18px}.bulk-enquiry{padding:14px 0}.bulk-enquiry summary{cursor:pointer;font-size:13px}.sub-actions:empty,.deadline-row:empty{display:none}.sub-actions .primary{font-size:15px}.stack-actions{display:grid;gap:10px;margin:14px 0}.stack-actions>button,.stack-actions>a{display:block;text-align:left;min-height:46px;white-space:normal;padding:12px 14px;border-radius:10px}.stack-actions>a{border:1px solid var(--line2);color:var(--text);text-decoration:none}.sticky-actions{position:sticky;bottom:-1px;background:var(--panel);padding:12px 0 calc(12px + env(safe-area-inset-bottom));z-index:2}.sticky-actions>button{width:100%}.history-date{display:flex;gap:12px;justify-content:space-between;align-items:center;font-size:12px;padding:10px 0;border-bottom:1px solid var(--line);flex-wrap:wrap}
.venue-result{display:block;width:100%;text-align:left;padding:12px;margin:5px 0;border:1px solid var(--line);border-radius:10px;background:var(--panel2);color:var(--text);min-height:48px}.venue-result strong{display:block}.venue-suggestions:not(:empty){padding:4px 0 14px}.venue-suggestions .section-label{margin:9px 0 4px}.attribution{font-size:10px;color:var(--muted)}.attribution a{color:inherit}.add-date-row{display:grid;grid-template-columns:1fr auto;gap:10px;align-items:end}.add-date-row .field{margin:0}.add-date-row button{min-height:46px;margin-bottom:1px}.candidate-entry{display:flex;align-items:center;gap:10px;padding:12px 0;border-bottom:1px solid var(--line)}.candidate-entry>div{flex:1;min-width:0}.candidate-entry strong{font-size:14px}.candidate-entry input{margin-top:6px;font-size:12px}.check-label{display:flex;align-items:center;gap:10px;min-height:44px;font-size:14px;cursor:pointer}.check-label input{width:20px;height:20px;flex:0 0 20px;margin:0}.extras-choices{border:0;margin:14px 0;padding:0;display:grid;grid-template-columns:1fr 1fr;gap:2px 12px}.extras-choices legend{font-size:13px;color:var(--muted);margin-bottom:8px}.personal-tools{margin-top:24px}.gig-day{margin:0 0 24px;border-color:var(--good-border);background:var(--good-surface)}.gig-day h2,.gig-day h3{font-size:24px;line-height:1.2;margin:12px 0}.arrival-hero{display:flex;align-items:baseline;gap:14px;font-size:15px;margin:12px 0}.arrival-hero strong{font-size:34px;font-variant-numeric:tabular-nums}.venue-contact,.venue-notes{border-top:1px solid var(--line);padding-top:16px;margin-top:16px}.notification-row{border-bottom:1px solid var(--line);padding:12px 0}.notification-row.urgent{border-left:3px solid var(--bad);padding-left:12px}.notification-link{display:block;border:0;background:transparent;color:var(--text);text-align:left;padding:7px 0;width:100%;min-height:44px}.notification-link strong{font-size:14px}.feedback-item{border-bottom:1px solid var(--line);padding:18px 0}.feedback-item small{display:block;overflow-wrap:anywhere;color:var(--muted);font-size:11px}.gig-notes,.venue-notes dd{white-space:pre-wrap;overflow-wrap:anywhere}select{width:100%;min-height:46px;border:1px solid var(--line2);border-radius:9px;padding:10px;background:var(--input-surface);color:var(--text);font:inherit}.form-grid>div{min-width:0}fieldset{min-width:0}.action-dialog{max-height:calc(100dvh - 24px);padding-bottom:calc(20px + env(safe-area-inset-bottom))}.toast button{min-height:44px;margin-left:8px}
@media(max-width:600px){.topbar{gap:4px}.account-area{gap:4px}.account-area .sync-pill{display:none}.brand{gap:5px}.brand span{font-size:19px}.notification-button{flex-basis:36px;width:36px;min-width:36px}.enquiry-card{padding:15px}.enquiry-card-head strong{font-size:16px}.enquiry-card-foot{display:block}.enquiry-card-foot .ready{display:block;margin-top:5px}.add-date-row{grid-template-columns:1fr}.add-date-row button{width:100%;margin:0 0 4px}.extras-choices{grid-template-columns:1fr}.enquiry-response .quick-controls button{font-size:12px;min-height:54px;padding:8px 3px}.enquiry-date .sub-actions button{font-size:12px}.action-dialog{max-width:calc(100vw - 16px);margin:8px auto}.venue-notes dt{max-width:110px}.gig-details dd{overflow-wrap:anywhere}.enquiry-card-head{gap:6px}}
@media(prefers-reduced-motion:reduce){*{scroll-behavior:auto!important}}

.creation-tabs button[aria-pressed=true]{background:var(--accent-fill);color:var(--primary-ink)}
@media(max-width:600px){.account-area{display:flex;align-items:center}.topbar{align-items:center;min-height:70px}.account-area .account-button{width:42px;height:42px}.notification-button{padding:6px}}

select:focus-visible{outline:2px solid var(--accent);outline-offset:3px}

/* Beta 4: consistent member artwork and static form actions. */
.member-mark,.member-avatar,.enquiry-own-row img,#accountIcon .member-mark{border-radius:50%;}
.member-mark{border-style:solid;overflow:visible;}.member-mark img,.member-avatar{border-radius:50%;object-fit:cover;}
.response-symbol{border-radius:50%;}.response-save{position:static;bottom:auto;box-shadow:none;margin-top:18px;}
.owner-response-row{display:flex;gap:10px;align-items:center;padding:10px 0;border-bottom:1px solid var(--line);}.owner-response-row>span{flex:1;}.owner-response-row small{display:block;line-height:1.5;}
.provenance{font-size:12px;color:var(--muted);line-height:1.6;margin-top:12px;}.password-fallback{margin:14px 0;}.password-fallback input{width:100%;margin:6px 0 12px;}.password-fallback summary{cursor:pointer;}
.cell-status{font-size:10px;letter-spacing:0;text-transform:none;}
.action-dialog{max-height:calc(100dvh - env(safe-area-inset-top) - env(safe-area-inset-bottom) - 24px);}.action-dialog input,.action-dialog select,.action-dialog textarea{font-size:16px;}@media(max-width:600px){.owner-response-row{flex-wrap:wrap;}.owner-response-row button{min-height:44px;}.action-dialog{width:calc(100% - 16px);}}

/* Member identity is the disc; availability is only the outer ring. */
[data-member="steve"]{--member-color:#6478d7;--member-filter:hue-rotate(28deg)}
[data-member="jon"]{--member-color:#ac78cc;--member-filter:hue-rotate(82deg)}
[data-member="colin"]{--member-color:#c19368;--member-filter:hue-rotate(190deg)}
[data-member="nick"]{--member-color:#6b9eb5;--member-filter:hue-rotate(350deg)}
[data-member="emma"]{--member-color:#ce8faf;--member-filter:hue-rotate(125deg)}
.member-mark,.member-mark.mini,.member-mark.small,.month-cell .member-mark.mini,#accountIcon .member-mark,.member-avatar,.enquiry-own-row img{border-radius:50%;background:var(--member-color,#6478d7);}
.member-mark{border:2px solid transparent;padding:1px;overflow:hidden;box-shadow:none;}
.member-mark img{border-radius:50%;object-fit:cover;transform:scale(1.18);filter:var(--member-filter,none);}
.member-avatar,.enquiry-own-row img{filter:var(--member-filter,none);object-fit:cover;}
.member-mark.available{border:2px solid var(--good)}
.member-mark.maybe{border:2px dashed var(--warn)}
.member-mark.unavailable{border:2px solid var(--bad);background:var(--member-color,#6478d7)}
.member-mark.unavailable img{filter:var(--member-filter,none);opacity:1}
/* h44 · A role icon a member picked is shown exactly as it looks in My icon: the per-member hue-rotate above is tuned
   for each member's original photo and would turn a picked icon's ring another colour. Originals keep their tint. */
.member-mark img[data-role-icon],img.member-avatar[data-role-icon],.enquiry-own-row img[data-role-icon]{filter:none}
.member-mark.unknown{border:2px dotted var(--muted)}
.member-mark.conditional{border:3px double var(--warn)}
.member-mark.identity{border:0;padding:0}
.member-mark.unavailable::after{content:none}
.response-symbol{display:none}
.agenda-title,.agenda-venue,.agenda-lifecycle,.agenda-summary{display:block;overflow-wrap:anywhere}
.agenda-venue{font-size:13px;color:var(--muted);margin-top:4px}
.agenda-lifecycle{font-size:11px;color:var(--muted);margin:5px 0 8px}
.agenda-summary{font-size:11px;color:var(--muted);margin-top:7px}
.agenda-body{min-width:0}.agenda-tail:empty{display:none}
.field{margin-bottom:16px}.field>label{display:block;margin-bottom:6px}
.form-grid{gap:16px;align-items:start}.form-section{margin-block:20px}
.dialog-actions,.sub-actions{gap:10px;align-items:center;flex-wrap:wrap}
.inline-error:not([hidden]){margin-block:12px;line-height:1.5}
.action-dialog input:not([type=checkbox]),.action-dialog select{min-height:46px}
#recordResponseForm .field{margin-block:12px}.password-fallback summary{line-height:1.5}
.shell-update{position:fixed;z-index:120;bottom:calc(90px + env(safe-area-inset-bottom));left:16px;right:16px;margin:auto;max-width:580px;display:flex;align-items:center;gap:12px;padding:14px;background:var(--panel);color:var(--text);border:1px solid var(--line2);border-radius:12px;box-shadow:0 4px 20px #0004;font-size:13px}
.shell-update button{flex-shrink:0}
@media(max-width:550px){.shell-update{flex-wrap:wrap}.agenda-row{grid-template-columns:42px minmax(0,1fr) auto}.agenda-tail{font-size:10px}}
/* Keep month summaries inside their date cells on narrow screens. */
@media(max-width:550px){.month-cell .cell-status,.month-cell .cell-life{max-width:100%;white-space:normal;overflow-wrap:anywhere;text-align:center}.month-cell .cell-status{font-size:9px}}

@media(max-width:400px){.month-cell .cell-status{font-size:8px;letter-spacing:0}}

/* iOS zooms the page when a focused field has text under 16px, and an installed web app can stay zoomed. Keep touch form text at 16px. */
@media(hover:none) and (pointer:coarse){input,select,textarea,.candidate-entry input{font-size:16px}}

/* styles.css styles the phone dialog as a bottom sheet under max-width:550px (margin:auto auto 0,
   rounded top corners only, and a .dialog-actions footer that hangs off the bottom edge). This file
   loads after it, and its max-width:600px block sets margin:8px auto at equal specificity, which won
   and left the dialog anchored to the top of the screen with square bottom corners on every phone.
   Restoring the margin here, last and narrower, puts the sheet back without touching 551-600px. */
@media(max-width:550px){.action-dialog{margin:auto auto 0}}

/* index.html sets viewport-fit=cover, so the page extends under the notch and the rounded corners and
   the app must inset content itself. The BOTTOM inset was handled from the start (nav, toast, dialog
   padding) but the horizontal ones never were — neither stylesheet referenced safe-area-inset-left or
   -right — so in landscape every container ran under the notch. In-flow content (.topbar, .app) is
   inset once here at body level. Fixed elements do not inherit that, so each is constrained: the nav
   and the update banner could both clip on a narrower landscape, and the sign-in overlay pads its
   gutters. The toast is handled by its own max-width rule in styles.css. */
body{padding-left:env(safe-area-inset-left);padding-right:env(safe-area-inset-right)}
.bottom-nav{width:min(520px,calc(100% - 2*max(env(safe-area-inset-left),env(safe-area-inset-right))))}
.shell-update{left:max(16px,env(safe-area-inset-left));right:max(16px,env(safe-area-inset-right))}
.auth-gate{padding-left:max(23px,env(safe-area-inset-left));padding-right:max(23px,env(safe-area-inset-right))}

/* h16 · Manage enquiry hero, availability colour coding, and one row shape for every notification. */
/* Grid, not wrapped flex: a long title must shrink beside the close button, never push it onto its own row.
   The back control takes a full row of its own above them when it is present, and no space when it is not. */
.dialog-head{display:grid;grid-template-columns:minmax(0,1fr) auto;align-items:center;column-gap:10px}
.dialog-head h2{min-width:0}
.dialog-back{grid-column:1/-1;justify-self:start;background:transparent;border:0;color:var(--accent);font-size:14px;font-weight:600;text-align:left;padding:8px 0;min-height:44px}
.enquiry-hero{margin:0 0 4px}
.enquiry-hero h3{font-size:21px;line-height:1.25;margin:0 0 8px}
.hero-when{font-size:16px;font-weight:600;margin:0 0 3px}
.hero-time{font-size:14px;margin:0 0 12px}
.hero-time.muted{color:var(--muted)}
.hero-status{font-size:13px;color:var(--muted);margin:0;padding-top:11px;border-top:1px solid var(--line)}
.hero-state{font-size:11px;font-weight:800;letter-spacing:.08em;color:var(--warn);margin:9px 0 0}
.owner-response-row .response-state{display:flex;align-items:center;gap:7px}
.owner-response-row .pip{width:8px;height:8px;border-radius:50%;background:var(--muted);flex:0 0 8px}
.owner-response-row.available .pip{background:var(--available)}
.owner-response-row.maybe .pip{background:var(--maybe)}
.owner-response-row.unavailable .pip{background:var(--unavailable)}
.owner-response-row.available .response-state{color:var(--available)}
.owner-response-row.maybe .response-state{color:var(--maybe)}
.owner-response-row.unavailable .response-state{color:var(--unavailable)}
.notice-list{display:grid;gap:24px}
.notice-group .section-label{margin:0 0 4px}
.notice-group-head{display:flex;align-items:baseline;justify-content:space-between;gap:12px}
.notice-mark-all{flex:0 0 auto;padding:8px 0 8px 10px;font-size:12px;white-space:nowrap}
.notice{display:flex;align-items:center;gap:8px;border-left:3px solid var(--line2);padding-left:13px;border-bottom:1px solid var(--line)}
.notice.action{border-left-color:var(--warn)}
.notice.urgent{border-left-color:var(--bad)}
.notice-link{display:flex;align-items:center;gap:10px;flex:1;min-width:0;border:0;background:transparent;color:var(--text);text-align:left;padding:13px 0;min-height:44px}
.notice-body{display:grid;gap:3px;flex:1;min-width:0}
.notice-title{font-size:15px;font-weight:600;line-height:1.35}
.notice-meta{font-size:12px;color:var(--muted);line-height:1.45}
.notice-tag{flex:0 0 auto;font-size:10px;font-weight:800;letter-spacing:.08em;color:var(--info);border:1px solid var(--info);border-radius:6px;padding:3px 6px}
.notice .text-button{flex:0 0 auto}
.delivery-problem{border-left:3px solid var(--bad);padding:2px 0 2px 13px;line-height:1.45}
.identity-card{margin:0 0 4px}
.identity-head{display:flex;align-items:center;gap:14px}
.identity-who{min-width:0}
.identity-who h1{font-size:22px;margin:0 0 2px;line-height:1.2}
.identity-who p{margin:0;font-size:13px}
.identity-email{color:var(--muted);word-break:break-word;margin-top:3px!important}
.identity-card .sub-actions{margin-top:6px}
.settings-group{margin:18px 0 6px}
.settings-group:first-of-type{margin-top:12px}

/* h17 · Gig Day reads as a time ladder; the sign-in card carries one action. */
.gig-day-address{color:var(--muted);font-size:13px;margin:2px 0 14px}
.time-ladder{display:grid;gap:1px;margin:0 0 16px;background:var(--line);border-radius:10px;overflow:hidden}
.time-ladder>div{display:flex;justify-content:space-between;align-items:baseline;gap:12px;background:var(--panel);padding:11px 13px}
.time-ladder dt{font-size:13px;color:var(--muted);margin:0}
.time-ladder dd{margin:0;font-size:19px;font-weight:700;font-variant-numeric:tabular-nums;letter-spacing:-.01em}
.gig-day-unset{color:var(--muted);font-size:13px;margin:0 0 14px}
.auth-intro{color:var(--muted);font-size:14px;margin:0 0 20px;text-align:center}
.auth-hint{color:var(--muted);font-size:12px;line-height:1.5;margin:10px 0 0}
/* Steve, 28 Sep: "clear and clean up the login screen UI for an excellent and simple UX. e.g. Sign in with your band
   email can be removed". The status line keeps its place under the button, where Sending…, Check your inbox… and
   every problem appear, but says nothing at rest and takes no room when empty. The hint is one line, centred, and no
   longer says there is no password (Other ways to sign in offers one). A new member's way in, which the member guide
   names, is a full-width outlined button under a hairline (never a second lime one), and the other ways sit last. */
.auth-hint{text-align:center}
.auth-message:empty{min-height:0;margin-top:0}
.auth-message{text-align:center}
.auth-join{margin-top:22px;padding-top:22px;border-top:1px solid var(--line)}
.signed-in-here .auth-join{display:none}
.auth-alternatives>summary{text-align:center}
.auth-alternatives{margin:10px 0 0}
.auth-foot{display:grid;gap:2px;justify-items:start}
.auth-foot:empty{display:none}
.gig-day-times{font-size:15px;margin:0 0 16px;line-height:1.5}
.gig-day-times strong{font-size:17px}
.gig-day-times.muted{color:var(--muted);font-size:13px}
/* h20 · .empty is sized for a whole page; inside an enquiry sheet its 24px padding stacked with the
   disclosure's 18px margin and .history's 27px left a large dead band when nothing needs answering. */
.enquiry-response .empty{padding:12px 0;text-align:left}
.enquiry-response>.more-details:last-of-type{margin-bottom:8px}
/* h21 · The Gig Day banner is Calendar-only and deliberately slight: on the day you want the facts, not a
   billboard. .dialog-actions sticks at bottom:-22px to cancel the dialog's bottom padding, but beta.css
   later changed that padding from 18px to 20px, so the bar no longer sat flush on its own edge. */
.gig-day-banner{padding:14px 16px;margin:0 0 18px}
.gig-day-banner .section-label{margin:0}
.gig-day-line{font-size:15px;line-height:1.5;margin:6px 0 10px}
.gig-day-line strong{font-size:17px}
.gig-day-banner .gig-day-address{margin:0 0 12px}
.gig-day-banner .sub-actions{margin:0}
/* Sticky bottom resolves against the scroller's PADDING edge. styles.css offsets it by a negative value
   meant to cancel the dialog's bottom padding, but beta.css later changed that padding and the two stopped
   agreeing — so the bar sat flush before it stuck and 21px higher after, which is the "floating" Steve saw.
   bottom:0 needs no such bookkeeping: the bar rests on the padding edge in both states. */
/* Steve: "Save gig should only be at the end of the sheet, it's fixed now, on the screen no matter where or
   how I scroll." The submit row was sticky, so it hovered over the form at every scroll position; three
   attempts at making it sit flush were all solving the wrong problem. It is static now, at the end of the
   form, which is what .response-save has done since Beta 3 — that precedent was already in this file. */
.action-dialog .dialog-actions{position:static;bottom:auto;margin-bottom:0;background:transparent;box-shadow:none;padding:16px 0 0;z-index:auto}
/* Declared here so the stylesheet carries the default; app.js overwrites it while a keyboard is open.
   Without this the variable exists only at runtime, which the Day/Night variable guard correctly rejects. */
:root{--keyboard-inset:0px;--keyboard-room:0px}
/* Extra scrollable space at the end of the sheet while a keyboard is open, so the submit row can be scrolled
   above iOS's floating AutoFill pill. Zero when no keyboard is present. */
#dialogBody{padding-bottom:var(--keyboard-room)}
/* Shrinking the sheet is not enough on its own: in landscape it is centred, so a shorter sheet just floats
   in the middle and still overlaps the keys. It has to be lifted by the same inset as well. */
.action-dialog{max-height:calc(100dvh - 24px - var(--keyboard-inset,0px));margin-bottom:calc(8px + var(--keyboard-inset,0px))}
@media(max-width:550px){
  /* Bottom sheets were sized purely by their content, so each one opened at a different height: Manage
     enquiry at y=24, Notifications at 387, Appearance at 619. The close button moved every time and a short
     sheet could not be swiped at all, because there was nothing to scroll and the page behind is locked —
     which is what reads as erratic. A floor on the height keeps them in one predictable band. */
  /* A floor, not a fixed height. Full height always was tried and measured well — close button spread 0,
     short content centred by 'safe center' rather than stranded — but it makes a full-screen takeover of
     choosing Day or Night, and the sheets used most often are full height under this rule anyway. To switch
     back: replace min-height with height, set max-height:none, and give #dialogBody flex:1 1 auto with
     justify-content:safe center. */
  .action-dialog{max-height:calc(100dvh - env(safe-area-inset-top) - env(safe-area-inset-bottom) - 24px - var(--keyboard-inset,0px));margin-bottom:var(--keyboard-inset,0px);min-height:min(70dvh, calc(100dvh - 24px - var(--keyboard-inset,0px)))}
  .action-dialog{display:flex;flex-direction:column}
  /* An author display beats the browser's own dialog:not([open]){display:none}: without this the closed sheet
     is drawn in the page (below the content on h35, over it on h36). */
  .action-dialog:not([open]){display:none}
  .dialog-head{flex:0 0 auto}
  /* A sheet taller than its content must not stretch that content down the page. */
  #dialogBody{flex:0 0 auto}
}

/* One and done: while this device holds a sign-in, the gate is only ever "Connecting…" or "Can't reach GigLock",
   never an invitation to request another magic link. app.js removes the class when the session truly ends. */
.signed-in-here #loginForm,.signed-in-here .auth-hint,.signed-in-here .auth-alternatives{display:none}

/* h36 · The gig card. The state is said once; the line-up lists every open task with its own button; then where,
   when and how to get there in the Gig Day sheet's shape, what to know at the venue, notes, the quiet row, Owner
   controls and the small print. One button grammar (14px on 44px) and one lime button per card. Existing tokens only,
   so the Day/Night variable guard and the contrast sweep cover it unchanged. */
.day-gig.conflict{border-color:var(--gig-conflict-border)}
.day-gig.critical{background:var(--gig-conflict-surface)}
.gig-head{flex-wrap:wrap;margin-bottom:8px}
.gig-head h2{font-size:21px;line-height:1.25;overflow-wrap:anywhere}
.gig-status{display:flex;flex-wrap:wrap;align-items:center;gap:6px 10px;margin:0 0 16px;font-size:13px;line-height:1.4;color:var(--detail-text)}
.gig-tag{font-size:10px;font-weight:800;letter-spacing:.08em;line-height:1.3;border:1px solid;border-radius:6px;padding:3px 7px;white-space:nowrap;color:var(--muted)}
.gig-tag.booked{color:var(--info)}
.gig-tag.draft{border-style:dashed}
.gig-tag.cancelled,.gig-tag.conflict{color:var(--bad)}
.gig-words{display:inline-flex;align-items:center;gap:7px}
.gig-words::before{content:"";flex:0 0 8px;width:8px;height:8px;border-radius:50%;background:var(--good)}
.gig-status-note,.gig-offline{font-size:13px;line-height:1.45;color:var(--detail-text);margin:-6px 0 16px}
.gig-offline strong{color:var(--warn)}
/* Line-up: the one home for reminders, deps and Jon on vocals. Open tasks share one tinted panel, in core.js's order;
   settled changes follow with the Notifications left rule. */
.gig-crew{margin:0 0 18px}
.gig-crew>.section-label,.gig-block>.section-label{font-size:12px;line-height:1.45;margin:0 0 8px}
.crew-tasks{border-left:3px solid var(--line2);border-radius:0 12px 12px 0;background:var(--panel2);padding:0 13px}
.crew-tasks.warn{border-left-color:var(--warn);background:var(--maybe-surface)}
.crew-tasks.critical{border-left-color:var(--bad);background:var(--conflict-surface)}
.crew-tasks>.crew-row{padding:11px 0 12px}
.crew-tasks>.crew-row+.crew-row{border-top:1px solid var(--line)}
.crew-tasks+.crew-row,.crew-row.good+.crew-row,.crew-row.cover+.crew-row{margin-top:12px}
.crew-row.good,.crew-row.cover{border-left:3px solid var(--good);padding:1px 0 1px 12px}
.crew-row.cover{border-left-color:var(--cover)}
.crew-title{font-size:14px;font-weight:700;line-height:1.35;overflow-wrap:anywhere}
.crew-detail{font-size:13px;line-height:1.45;color:var(--detail-text);margin-top:2px;overflow-wrap:anywhere}
.crew-row .sub-actions{margin-top:10px}
/* Where, when, go: the Gig Day sheet's order, so the two read as one object. */
.gig-venue{font-size:17px;font-weight:700;line-height:1.3;overflow-wrap:anywhere}
.gig-address{font-size:13px;line-height:1.45;color:var(--muted);margin-top:2px;overflow-wrap:anywhere}
.gig-core>.time-ladder,.gig-core>.gig-day-unset{margin:14px 0 0}
.gig-core>:first-child,.gig-core>.sr-only+*{margin-top:0}
.gig-core .time-ladder{border:1px solid var(--line)}
.gig-core .time-ladder>div{background:var(--panel2)}
.is-history .time-ladder dd{font-size:16px;font-weight:600;color:var(--muted)}
.gig-set-line{font-size:13px;line-height:1.45;color:var(--detail-text);margin-top:10px}
.gig-go{margin-top:14px}
.gig-go-alt{display:flex;justify-content:center;margin-top:2px}
.gig-go-alt>.text-button{font-size:13px}
/* One button grammar across the card: 14px labels on 44px targets, links drawn as secondary buttons. */
.gig-body .sub-actions>button,.gig-more>button{min-height:44px;padding:10px 14px;border-radius:11px;font-size:14px}
.gig-body .sub-actions>.text-button,.gig-more>.text-button{padding:10px 6px;font-size:13px}
.gig-block{border-top:1px solid var(--line);margin-top:18px;padding-top:14px}
.gig-block .gig-details,.gig-block .gig-notes{margin:0}
.gig-venue-notes{grid-template-columns:minmax(0,110px) 1fr}
.gig-contact{display:flex;align-items:center;justify-content:space-between;flex-wrap:wrap;gap:8px 12px}
.gig-venue-notes+.gig-contact{border-top:1px dashed var(--line);margin-top:12px;padding-top:12px}
.gig-contact-who{min-width:0;overflow-wrap:anywhere}
.gig-contact-who strong{display:block;font-size:14px}
.gig-contact-who small{display:block;color:var(--muted)}
.gig-contact>.sub-actions{margin:0}
.gig-contact .sub-actions>a{min-height:44px;min-width:76px;padding:10px 14px;border-radius:11px;justify-content:center;background:var(--panel2);color:var(--text);font-size:14px;font-weight:650}
/* The quiet row. A subscriber's calendar line is a status that opens its sheet; the tick and chevron are generated
   content with empty alternative text, so the button's name stays exactly "In your calendar subscription". */
.gig-more{border-top:1px solid var(--line);margin-top:18px;padding-top:14px}
.gig-more>.text-button.subscribed-note{flex:1 0 100%;display:flex;align-items:center;justify-content:flex-start;gap:8px;text-align:left;padding:8px 0;font-size:13px;font-weight:650;color:var(--detail-text)}
.gig-more>.subscribed-note::before{content:"\2713";content:"\2713" / "";color:var(--good);font-weight:800}
.gig-more>.subscribed-note.later::before{content:none}
.gig-more>.subscribed-note::after{content:"\203A";content:"\203A" / "";margin-left:auto;color:var(--muted);font-size:19px;font-weight:400;line-height:1}
/* Owner controls: Edit gig and, beside it, Cancel gig (Delete enquiry on a draft) in the danger style. h43 D25: no
   disclosure in front of it any more; one tap opens the confirmation card, which says what it costs. */
.gig-owner>.sub-actions{margin-top:0}
.gig-foot{border-top:1px solid var(--line);margin-top:18px;padding-top:12px}
.gig-foot>.provenance{margin:0;line-height:1.55}
.gig-foot>.attribution{margin-top:4px}
.day-gig>.gig-body+button{margin-top:16px}
@media(max-width:550px){
  .gig-head h2{font-size:20px}
  .gig-venue-notes{grid-template-columns:1fr;gap:2px}
  .gig-venue-notes dd+dt{margin-top:8px}
  .gig-go>button:not(.text-button),.gig-more>button:not(.text-button),.gig-owner>.sub-actions>button{flex:1 1 auto}
  .gig-contact>.sub-actions{flex:1 1 100%}
  .gig-contact .sub-actions>a{flex:1 1 0}
}
/* h36 review: multi-line venue notes keep their breaks; the open-task panel stays visible on a critical card */
.gig-venue-notes dd{white-space:pre-wrap;overflow-wrap:anywhere}
.day-gig.critical .crew-tasks{background:var(--panel)}
/* h38 · Manage enquiry and the enquiry card. Task first, in the h36 gig card's grammar: the state said once; the dates
   grouped by what can be done with them, each with its own buttons; one lime button per sheet; deadlines in the Gig Day
   ladder with the one control that changes them; At the venue, Notes, Owner controls, small print. New classes are
   prefixed enq-. Existing tokens only. */

/* The enquiry card. A <button> inherits font-weight 650, which made every line of the old card bold. */
.enq-card{font-weight:400;padding:16px 16px 14px}
.enq-card .enquiry-card-head{align-items:center}
.enq-card .enquiry-card-head strong{min-width:0;font-size:17px;font-weight:750;line-height:1.3;overflow-wrap:anywhere}
.enq-card-meta{display:block;margin-top:3px;font-size:13px;line-height:1.45;color:var(--muted);overflow-wrap:anywhere}
.enq-card-meta .deadline{font-size:inherit}
.enq-card-meta .deadline.due{color:var(--warn);font-weight:650}
.enq-chips{display:flex;flex-wrap:wrap;gap:6px;margin-top:11px}
.enq-chip{display:inline-flex;align-items:center;gap:5px;min-height:28px;padding:3px 10px 3px 8px;border:1px solid var(--line);border-radius:999px;background:var(--panel2);font-size:12px;font-weight:600;line-height:1.2;color:var(--detail-text);white-space:nowrap}
.enq-glyph{font-size:12px;font-weight:800;line-height:1;color:var(--muted)}
.enq-chip.ready .enq-glyph,.enq-chip.available .enq-glyph{color:var(--good)}
.enq-chip.blocked .enq-glyph,.enq-chip.unavailable .enq-glyph{color:var(--bad)}
.enq-chip.maybe .enq-glyph{color:var(--warn)}
.enq-chip.waiting,.enq-chip.unknown{border-style:dashed}
.enq-chip.more{color:var(--muted);font-weight:500}
.enq-next{display:flex;align-items:center;justify-content:space-between;gap:10px;margin-top:13px;padding-top:11px;border-top:1px solid var(--line);font-size:14px;font-weight:650;line-height:1.4;color:var(--detail-text);overflow-wrap:anywhere}
.enq-next.act{color:var(--accent)}
.enq-go{flex:0 0 auto;font-size:21px;font-weight:400;line-height:1;color:var(--muted)}
.gig-tag.enq-live{color:var(--info);border-style:dashed}
.gig-tag.enq-expired{color:var(--warn)}
.enq-card.enq-history{padding:12px 16px;margin-bottom:8px}
.enq-card.enq-history .enquiry-card-head strong{font-size:15px}

/* Head: venue, when, then the state as a tag and words, the gig card's status row. */
.enq-manage .enq-head{margin:0 0 4px}
.enq-manage .enq-head h3{font-size:21px;line-height:1.25;margin:0 0 3px;overflow-wrap:anywhere}
.enq-manage .hero-when{font-size:14px;font-weight:600;line-height:1.4;color:var(--detail-text);margin:0 0 10px}
.enq-status{margin:0 0 14px}
.enq-status #enquiryProgress{font-weight:600;color:var(--text)}
.enq-due{display:inline-flex;align-items:center;gap:7px;color:var(--warn);font-weight:650}
.enq-due::before{content:"";flex:0 0 8px;width:8px;height:8px;border-radius:50%;background:var(--warn)}
.enq-manage .gig-status-note{margin:-6px 0 14px}
.enq-manage .gig-offline{margin:-6px 0 14px}
.enq-chosen{margin:4px 0 6px}

/* Undo says what happened, at the top of the sheet, where it can be seen. */
.enq-undo{display:flex;align-items:center;justify-content:space-between;gap:10px;margin:0 0 14px;padding:2px 4px 2px 14px;border:1px solid var(--line2);border-radius:12px;background:var(--toast-surface);font-size:14px;font-weight:600;line-height:1.35}
.enq-undo .text-button{min-height:44px;color:var(--accent);font-size:14px;font-weight:750}

/* The dates, grouped by what can be done with them. */
.enq-group{margin-top:18px}
.enq-group>.section-label{font-size:12px;line-height:1.45;margin:0 0 2px}
.enq-group .enq-chase{margin:8px 0 6px}
.enq-manage .enq-date{padding:14px 0 4px;border-top:1px solid var(--line)}
.enq-group>.section-label+.enq-date,.enq-lapsed-note+.enq-date{border-top:0;padding-top:8px}
.enq-date h4{font-size:16px;line-height:1.3;margin:0}
.enq-why{display:flex;gap:8px;align-items:baseline;font-size:13px;line-height:1.45;color:var(--detail-text);margin:3px 0 0;overflow-wrap:anywhere}
.enq-why::before{content:"";flex:0 0 8px;width:8px;height:8px;border-radius:50%;background:var(--muted);transform:translateY(-1px)}
.enq-why.good::before{background:var(--good)}
.enq-why.cover::before{background:var(--cover)}
.enq-why.dep::before{background:var(--warn)}
.enq-why.wait::before{background:transparent;border:2px dotted var(--waiting-text);width:5px;height:5px;flex-basis:5px}
.enq-why.bad{color:var(--bad)}
.enq-why.bad::before{background:var(--bad)}
.enq-date-note{font-size:12px;line-height:1.45;color:var(--muted);margin:3px 0 0 16px;overflow-wrap:anywhere}
.enq-lapsed-note{margin:4px 0 0}

/* One button grammar, as on the gig card: 14px labels on 44px targets. Mark not viable is a quiet text button set
   apart at the end of the row, so it is never the neighbour of the lime Book. */
.enq-manage .sub-actions>button:not(.text-button){min-height:44px;padding:10px 14px;border-radius:11px;font-size:14px}
.enq-manage .sub-actions>.text-button{min-height:44px;padding:10px 6px;font-size:13px}
.enq-acts{margin-top:10px;gap:8px}
.enq-acts>.enq-drop{margin-left:auto;color:var(--muted)}
.enq-acts>button:first-child:not(.text-button){min-width:148px}

/* The line-up behind each date: its face is the calendar's five rings, so who is in reads without opening it. */
.enq-lineup{margin:2px 0 6px;padding-top:0}
.enq-lineup>summary{display:flex;align-items:center;gap:10px;min-height:44px;padding:6px 0;margin:0;font-size:13px;color:var(--muted);list-style:none}
.enq-lineup>summary::-webkit-details-marker{display:none}
.enq-lineup>summary::after{content:"\203A";content:"\203A" / "";margin-left:auto;font-size:20px;line-height:1;color:var(--muted);transform:rotate(90deg)}
.enq-lineup[open]>summary::after{transform:rotate(-90deg)}
.enq-lineup[open]>summary{margin-bottom:2px}
.enq-marks{display:inline-flex;gap:3px;flex:0 0 auto}
.enq-marks .member-mark.mini{width:26px;height:26px}
.enq-lineup .owner-response-row{padding:8px 0}
.enq-lineup .owner-response-row:last-child{border-bottom:0}
.enq-lineup .owner-response-row .member-avatar{width:32px;height:32px}
.enq-lineup .owner-response-row button{min-height:44px;padding:8px 12px;border-radius:11px;font-size:13px}

/* Deadlines in the Gig Day ladder's shape. */
.enq-deadlines .time-ladder{margin:0;border:1px solid var(--line)}
.enq-deadlines .time-ladder>div{align-items:center;background:var(--panel2)}
.enq-ladder dt{display:grid;gap:1px;color:var(--detail-text)}
.enq-ladder dt small{font-size:12px;color:var(--muted)}
.enq-ladder dd{font-size:17px;text-align:right}
.enq-ladder .due dd,.enq-ladder .due dt small{color:var(--warn)}
.enq-ladder .past dd,.enq-ladder .past dt small{color:var(--bad)}
.enq-deadlines>.sub-actions{margin-top:12px}
.enq-deadlines>.gig-day-unset{margin:0}

/* Dates no longer offered, At the venue, Notes. */
.enq-manage .enq-other{margin-top:16px}
.enq-manage .enq-other+.gig-block{margin-top:6px}
.enq-manage .history-date{flex-wrap:nowrap;font-size:14px;min-height:52px;padding:6px 0}
.enq-manage .history-date:last-child{border-bottom:0}
.enq-hist-when{display:grid;gap:1px;min-width:0}
.enq-hist-when small{font-size:12px;color:var(--muted)}
.enq-address{margin:0}
.enq-address+.gig-venue-notes,.enq-address+.inline-note,.enq-address+.gig-contact{margin-top:12px}
.enq-manage .gig-owner{margin-top:18px}

/* Record a member's answers: the respond sheet's three choices, plus No answer, one block per date.
   h40: the date was a floated <legend>, which took itself out of the flow and left the choices free to ride up
   into it — the collision in Steve's screenshot. The block is a labelled group now, so the date is an ordinary
   heading in normal flow and nothing below it can move up. */
.enq-rec-who{display:flex;align-items:center;gap:12px;margin:0 0 10px}
.enq-rec-who .member-avatar{width:44px;height:44px;flex:0 0 44px}
.enq-rec-who strong{display:block;font-size:16px;line-height:1.3}
.enq-rec-who small{display:block;font-size:13px;color:var(--muted)}
.enq-rec-intro{font-size:14px;line-height:1.5;color:var(--detail-text);margin:0 0 4px}
.enq-rec-date{margin:0;padding:16px 0 12px;border:0;border-top:1px solid var(--line);min-width:0}
.enq-rec-when{margin:0;font-size:16px;font-weight:700;line-height:1.3;overflow-wrap:anywhere}
.enq-rec-by{font-size:12px;color:var(--muted);margin:4px 0 0}
.enq-rec-kept{font-size:14px;line-height:1.45;color:var(--detail-text);margin:8px 0 0}
.enq-rec-choices{margin-top:12px}
.enq-rec-choice{position:relative;display:flex;align-items:center;justify-content:center;min-height:50px;margin:0;padding:6px 4px;border:1px solid var(--line);border-radius:11px;background:var(--panel2);font-size:13px;font-weight:650;text-align:center;cursor:pointer}
.enq-rec-choice input{position:absolute;inset:0;width:100%;height:100%;min-height:0;margin:0;padding:0;border:0;opacity:0;cursor:pointer}
.enq-rec-choice[data-status=available]{color:var(--good)}
.enq-rec-choice[data-status=maybe]{color:var(--warn)}
.enq-rec-choice[data-status=unavailable]{color:var(--bad)}
.enq-rec-choice:has(input:checked){border-width:2px;font-weight:800;box-shadow:inset 0 -2px currentColor}
.enq-rec-choice[data-status=available]:has(input:checked){border-color:var(--good);background:var(--good-surface)}
.enq-rec-choice[data-status=maybe]:has(input:checked){border-color:var(--warn);background:var(--maybe-surface)}
.enq-rec-choice[data-status=unavailable]:has(input:checked){border-color:var(--bad);background:var(--bad-surface)}
.enq-rec-choice:has(input:focus-visible){outline:3px solid var(--focus);outline-offset:2px}
/* No answer is the state a date starts in, so it sits under the three answers rather than beside them: the row of
   three keeps its width at 375px, and the choice that clears a date reads as the different thing it is. */
.enq-rec-choice[data-status=unknown]{grid-column:1/-1;min-height:44px;margin-top:5px;border-style:dashed;background:transparent;color:var(--muted)}
.enq-rec-choice[data-status=unknown]:has(input:checked){border-style:solid;border-color:var(--line2);background:var(--panel2);color:var(--text)}
.enq-rec-date .available-after{margin:12px 0 0}

/* Extend deadline says what the two dates do. */
.enq-extend-intro{font-size:14px;line-height:1.5;color:var(--detail-text);margin:0 0 10px}
.enq-extend-gone{display:flex;gap:8px;align-items:baseline;font-size:14px;font-weight:650;line-height:1.45;color:var(--warn);margin:0 0 12px}
.enq-extend-gone::before{content:"";flex:0 0 8px;width:8px;height:8px;border-radius:50%;background:var(--warn)}

@media(max-width:550px){
  .enq-manage .enq-head h3{font-size:20px}
  .enq-chase .sub-actions>button,.enq-deadlines .sub-actions>button,.enq-manage .gig-owner>.sub-actions>button{flex:1 1 auto}
  .enq-manage .gig-contact>.sub-actions{flex:1 1 100%}
  .enq-manage .gig-contact .sub-actions>a{flex:1 1 0}
  .enq-rec-choice{min-height:54px;font-size:12px}
}

/* h38 · The Gigs list, task first. Needs you (a card per item, ending in its one step), In progress (someone else's
   move), All set (booked, nothing open) and one History. Cards and rows share the Calendar list's date column and the
   h36 gig card's grammar: tags said once, open tasks in its tinted panel, settled changes with its green or teal rule,
   where and when in the Gig Day ladder's words. One lime button on the page. New classes are prefixed glist-. Existing
   tokens only. */
.glist-page{max-width:760px;margin:0 auto}
.glist-section>.section-label{margin:0 0 10px}
.add-action.quiet{background:var(--panel2);color:var(--text);border:1px solid var(--line2)}
.add-action.quiet:hover{background:var(--hover)}
.glist-page>.calendar-note{margin:0 1px 4px;font-size:12px}
.glist-clear{display:flex;align-items:center;gap:9px;margin:22px 0 0;font-size:14px;line-height:1.45;color:var(--detail-text)}
.glist-clear::before{content:"";flex:0 0 8px;width:8px;height:8px;border-radius:50%;background:var(--good)}
.glist-empty p+p{margin-top:6px;font-size:14px;line-height:1.5;color:var(--detail-text)}
.glist-empty strong{font-size:16px}
/* The date column: weekday (Today, in accent, on the day), day, month, and the year when it isn't this one. */
.glist-date{flex:0 0 48px;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:1px;min-height:60px;padding:6px 0;border:1px solid var(--line);border-radius:11px;background:var(--panel2);color:var(--muted);font-size:10px;font-weight:750;letter-spacing:.06em;text-transform:uppercase;line-height:1.2;font-variant-numeric:tabular-nums}
.glist-date strong{font-size:21px;font-weight:800;letter-spacing:-.02em;line-height:1.05;color:var(--text)}
.glist-dashed{border-style:dashed}
.glist-today>span:first-child{color:var(--accent)}
.glist-year{letter-spacing:.02em}
.glist-count>span{letter-spacing:.04em}
/* Head: title, the state in tags and words, how far off, where, when. */
.glist-head{display:flex;align-items:flex-start;gap:12px}
.glist-what{flex:1 1 auto;min-width:0;display:flex;flex-direction:column;gap:3px}
.glist-title{margin:0;font-size:16px;font-weight:750;line-height:1.3;letter-spacing:-.01em;color:var(--text);overflow-wrap:anywhere}
.glist-status{display:flex;flex-wrap:wrap;align-items:center;gap:5px 8px;margin:2px 0 1px;font-size:13px;line-height:1.4;color:var(--detail-text)}
.glist-rel{font-size:12px;font-weight:650;color:var(--muted)}
.glist-where{font-size:13px;font-weight:600;line-height:1.4;color:var(--detail-text);overflow-wrap:anywhere}
.glist-when,.glist-due{font-size:13px;line-height:1.4;color:var(--muted)}
.glist-when b{font-weight:750;color:var(--text);font-variant-numeric:tabular-nums}
.glist-due .deadline{font-size:inherit}
.glist-warn{color:var(--warn);font-weight:650}
/* The open line-up tasks in the h36 panel, the settled changes with its rule, and one line of who acts. */
.glist-body{margin:12px 0 0}
.glist-tasks{display:block;margin-top:4px;border-left:3px solid var(--line2);border-radius:0 10px 10px 0;background:var(--panel2);padding:1px 12px}
.glist-tasks.warn{border-left-color:var(--warn);background:var(--maybe-surface)}
.glist-tasks.critical{border-left-color:var(--bad);background:var(--conflict-surface)}
.glist-card.critical .glist-tasks,.glist-row.critical .glist-tasks{background:var(--panel)}
.glist-task{display:block;padding:7px 0;font-size:13px;font-weight:600;line-height:1.4;color:var(--text);overflow-wrap:anywhere}
.glist-task+.glist-task{border-top:1px solid var(--line)}
.glist-task.mine{font-weight:800}
.glist-settled{display:block;margin-top:8px;border-left:3px solid var(--good);padding:1px 0 1px 10px;font-size:13px;font-weight:600;line-height:1.4;color:var(--detail-text);overflow-wrap:anywhere}
.glist-settled.cover{border-left-color:var(--cover)}
.glist-line{display:block;margin-top:4px;font-size:13px;line-height:1.45;color:var(--detail-text);overflow-wrap:anywhere}
.glist-line.act{color:var(--accent);font-weight:750}
.glist-line.act::after{content:" \203A";content:" \203A" / ""}
.glist-chips{margin-top:12px}
/* Needs you: a card, then its one step. The step's target is stretched over the card, so the whole card is that one
   button; nothing else on the card is a control. */
.glist-card{position:relative;margin:0 0 12px;padding:14px;border:1px solid var(--line);border-radius:16px;background:var(--panel)}
.glist-card.conflict{border-color:var(--gig-conflict-border)}
.glist-card.critical{background:var(--gig-conflict-surface)}
.glist-card:hover{border-color:var(--line2)}
.glist-card.conflict:hover{border-color:var(--bad)}
.glist-step{margin-top:12px;padding-top:12px;border-top:1px solid var(--line)}
.glist-why{margin:0 0 10px;font-size:13px;line-height:1.45;color:var(--detail-text);overflow-wrap:anywhere}
.glist-go{display:flex;align-items:center;justify-content:center;gap:10px;width:100%;min-height:44px;padding:10px 14px;border-radius:11px;font-size:15px;line-height:1.3}
.glist-go::after{content:"";position:absolute;inset:0;border-radius:16px}
.glist-go>.glist-chev{font-size:20px;font-weight:400;line-height:1;opacity:.7}
/* In progress, All set, History and Me: one row per item, one tap target. */
.glist-row{display:flex;align-items:flex-start;gap:12px;width:100%;margin:0 0 8px;padding:12px;border:1px solid var(--line);border-radius:14px;background:var(--panel);text-align:left;font-weight:400;color:var(--text)}
.glist-row:hover{background:var(--hover)}
.glist-row.conflict{border-color:var(--gig-conflict-border)}
.glist-row.critical{border-color:var(--gig-conflict-border);background:var(--gig-conflict-surface)}
.glist-row .glist-date{min-height:56px}
.glist-row .glist-chips{margin-top:6px}
.glist-past{padding:10px 12px}
.glist-past .glist-title{font-size:15px}
.glist-past .glist-date{min-height:50px}
.glist-past .glist-date strong{font-size:19px;color:var(--detail-text)}
.glist-month{display:flex;align-items:center;gap:10px;margin:16px 0 8px;font-size:13px;font-weight:700;color:var(--muted)}
.glist-month::after{content:"";flex:1;border-top:1px solid var(--line)}
.glist-section>.section-label+.glist-month{margin-top:0}
.glist-history[open]>summary{margin-bottom:10px}
/* The Day card control a Gigs step landed on, for a moment. */
.glist-landed{outline:3px solid var(--focus);outline-offset:3px}
@media(min-width:551px){.glist-go{display:inline-flex;width:auto;min-width:220px}}
@media(max-width:550px){
  .glist-card{padding:13px 12px}
  .glist-head,.glist-row{gap:11px}
  .glist-date{flex-basis:46px}
}

/* h38 · The gig form: Add Gig, Repeat gig, Edit draft, Edit gig, Book this date. Top to bottom in the order the task
   happens: what the sheet started from, the date and what it means for the band (the line-up's words and tones), where,
   the times as the card's ladder, the optional details, then one decision and one lime button. Every new class is gform-.
   Existing tokens only, so the Day/Night variable guard and the contrast sweep cover it unchanged. */
/* Sections are headed like the gig card's blocks. A legend floats so its section's hairline runs unbroken. The shared
   venue fieldset and the Date Enquiry side of Add Gig use the same labels, so the two sides read as one form. */
.gform .form-section>legend,.gform-venue>legend,#enquiryForm>.form-section>legend{float:left;width:100%;padding:0;margin:0 0 10px;font-size:12px;font-weight:700;line-height:1.45;color:var(--muted);letter-spacing:.07em;text-transform:uppercase}
.gform .form-section>legend+*,.gform-venue>legend+*,#enquiryForm>.form-section>legend+*{clear:both}
.gform .field>label small,.gform-venue .field>label small{font-size:12px;font-weight:500;color:var(--muted);margin-left:6px}
.gform input[type=checkbox]{accent-color:var(--mine-border)}
/* Add Gig asks one question first. The chosen side is neutral: the submit stays the sheet's one lime button. */
.creation-tabs{margin-bottom:8px}
.creation-tabs button[aria-pressed=true]{background:var(--panel);color:var(--text);box-shadow:0 0 0 1px var(--line2)}
.gform-mode-hint{font-size:13px;line-height:1.45;color:var(--detail-text);margin:0 0 18px}
/* Blocks are hairline-separated, as on the card. */
.gform>.gform-block{min-width:0;border:0;border-top:1px solid var(--line);margin:20px 0 0;padding:14px 0 0}
.gform>.gform-block:first-child{border-top:0;margin-top:0;padding-top:0}
.gform>.gform-block>.section-label{display:block;font-size:12px;line-height:1.45;margin:0 0 10px}
.gform-when>.field{margin-bottom:10px}
.gform-when>.field>label.section-label{display:block;font-size:12px;line-height:1.45;margin:0 0 10px;color:var(--muted)}
/* What the sheet started from: the card's own status tags on an edit, the source of a repeat. */
.gform-status{margin:0}
.gform-status-name{font-size:14px;font-weight:650;color:var(--text);overflow-wrap:anywhere}
.gform-source{font-size:13px;line-height:1.5;color:var(--detail-text);border-left:3px solid var(--line2);padding:2px 0 2px 12px;margin:0;overflow-wrap:anywhere}
.gform-source strong{color:var(--text)}
/* Book this date: the enquiry's facts, read-only, in the time ladder's shape. */
.gform-facts{display:grid;gap:1px;margin:0;background:var(--line);border:1px solid var(--line);border-radius:12px;overflow:hidden}
.gform-facts>div{display:grid;grid-template-columns:124px minmax(0,1fr);gap:12px;align-items:baseline;background:var(--panel2);padding:11px 13px}
.gform-facts dt{font-size:13px;line-height:1.35;color:var(--muted);margin:0}
.gform-facts dd{margin:0;font-size:15px;font-weight:700;line-height:1.35;overflow-wrap:anywhere}
.gform-facts>div:first-child dd{font-size:17px;font-weight:750}
.gform-facts dd small{display:block;font-size:13px;font-weight:500;line-height:1.4;color:var(--detail-text);margin-top:2px}
.gform-facts .gform-due dd small{display:inline;margin:0}
.gform-facts .gform-due.due dd small{color:var(--warn);font-weight:700}
.gform-facts .gform-due.past dd small{color:var(--bad);font-weight:700}
.gform-note{font-size:13px;line-height:1.45;color:var(--detail-text);margin:10px 0 12px}
/* The band check under the date: the line-up panel's shape and tones, so a date reads the same here as on the card. */
.gform-check{border-left:3px solid var(--line2);border-radius:0 12px 12px 0;background:var(--panel2);color:var(--text);padding:11px 13px 12px}
.gform-check.quiet{border-left:0;border-radius:0;background:transparent;padding:0}
.gform-check.good{border-left-color:var(--good);background:var(--good-surface)}
.gform-check.cover{border-left-color:var(--cover);background:var(--cover-surface)}
.gform-check.warn{border-left-color:var(--warn);background:var(--maybe-surface)}
.gform-check.critical{border-left-color:var(--bad);background:var(--conflict-surface)}
.gform-check-day{font-size:11px;font-weight:800;line-height:1.4;letter-spacing:.08em;text-transform:uppercase;color:var(--detail-text);margin:0 0 4px}
.gform-check-title{font-size:14px;font-weight:700;line-height:1.35;overflow-wrap:anywhere}
.gform-check-detail{font-size:13px;line-height:1.45;color:var(--detail-text);margin-top:2px;overflow-wrap:anywhere}
.gform-check.quiet .gform-check-detail{color:var(--muted);margin:0}
.gform-check-marks{display:flex;flex-wrap:wrap;gap:6px;margin-top:10px}
.gform-check-hint{font-size:13px;line-height:1.45;color:var(--detail-text);margin-top:8px;overflow-wrap:anywhere}
.gform-check .sub-actions{margin-top:10px}
.gform-check .sub-actions>button{min-height:44px;padding:10px 14px;border-radius:11px;font-size:14px}
/* Where. The saved-venues note sits under the address it is about. */
.gform-venue-saved{margin:-8px 0 0}
/* Disclosures that say what they hold, on a 48px row with the quiet row's chevron. No flex on summary (older WebKit). */
.gform-more,.gform-venue-more{margin:14px 0 0;padding:0;border:1px solid var(--line);border-radius:12px;background:var(--panel)}
.gform-more>summary,.gform-venue-more>summary{position:relative;display:block;list-style:none;min-height:48px;margin:0;padding:13px 40px 13px 14px;font-size:14px;font-weight:650;line-height:1.5;color:var(--text);cursor:pointer}
.gform-more>summary::-webkit-details-marker,.gform-venue-more>summary::-webkit-details-marker{display:none}
.gform-more>summary::after,.gform-venue-more>summary::after{content:"\203A";content:"\203A" / "";position:absolute;right:15px;top:50%;margin-top:-11px;font-size:19px;font-weight:400;line-height:22px;color:var(--muted);transform:rotate(90deg)}
.gform-more[open]>summary::after,.gform-venue-more[open]>summary::after{transform:rotate(-90deg)}
.gform-more[open]>summary,.gform-venue-more[open]>summary{border-bottom:1px solid var(--line)}
.gform-filled{font-weight:500;font-size:13px;color:var(--muted);overflow-wrap:anywhere}
.gform-more>:not(summary),.gform-venue-more>:not(summary){margin-left:14px;margin-right:14px}
.gform-more>summary+*,.gform-venue-more>summary+*{margin-top:14px}
.gform-more>:last-child,.gform-venue-more>:last-child{margin-bottom:14px}
.gform-venue-more textarea{min-height:64px;field-sizing:content;max-height:200px}
/* Times: the gig card's ladder, with a field on each rung. */
.gform-ladder{display:grid;gap:1px;background:var(--line);border:1px solid var(--line);border-radius:12px;overflow:hidden}
.gform-rung{display:flex;align-items:center;justify-content:space-between;gap:12px;background:var(--panel2);padding:6px 6px 6px 14px;min-height:58px}
.gform-rung>label{margin:0;min-width:0;font-size:15px;font-weight:650;line-height:1.3;color:var(--text)}
.gform-rung>label small{display:block;font-size:12px;font-weight:500;color:var(--muted);margin-top:1px}
.gform-rung>.timefield{flex:0 0 136px;width:136px;min-height:46px;margin:0;padding-right:16px;font-size:17px;font-weight:700;font-variant-numeric:tabular-nums}
.gform-rung.problem{background:var(--conflict-surface);box-shadow:inset 3px 0 var(--bad)}
.gform-rung.problem>.timefield{border-color:var(--bad)}
.gform-times-note{font-size:13px;line-height:1.45;color:var(--detail-text);margin:8px 0 0}
.gform-times-note.problem{color:var(--bad);font-weight:650}
/* Details: the name, the notes (visible, growing with their text), then sets and extras as one-tap choices. */
.gform-details>.field{margin-bottom:14px}
.gform-details textarea{min-height:84px;field-sizing:content;max-height:260px}
.gform-ref{margin:8px 0 0;padding:2px 0 2px 12px;border-left:3px solid var(--line2);font-size:13px;line-height:1.45;color:var(--notes-text);white-space:pre-wrap;overflow-wrap:anywhere}
.gform-ref>span{display:block;font-size:11px;font-weight:800;letter-spacing:.08em;text-transform:uppercase;color:var(--muted);white-space:normal}
.gform-options{min-width:0;border:0;padding:0;margin-top:14px}
.gform-options>legend{padding:0;margin:0 0 8px;font-size:12px;font-weight:700;color:var(--notes-text)}
.gform-sets-more{margin-top:12px}
.gform-sets-more .field{margin-bottom:0}
.gform-pills{display:grid;grid-template-columns:1.6fr repeat(4,minmax(0,1fr));gap:6px}
.gform-chips{display:flex;flex-wrap:wrap;gap:8px}
/* The input covers its whole label, invisible but still what is tapped, focused and read out; the span is what is drawn. */
.gform-pill,.gform-chip,.gform-choice{position:relative;display:block;margin:0}
.gform-pill>input,.gform-chip>input,.gform-choice>input{position:absolute;inset:0;width:100%;height:100%;margin:0;opacity:0;cursor:pointer;z-index:1}
.gform-pill>span,.gform-chip>span{display:flex;align-items:center;justify-content:center;min-height:44px;padding:0 14px;border:1px solid var(--line2);border-radius:22px;background:var(--panel);color:var(--text);font-size:14px;font-weight:600;line-height:1.2;text-align:center}
.gform-pill>span{padding:0 6px}
.gform-pill>input:checked+span,.gform-chip>input:checked+span,.gform-choice>input:checked+span{border-color:var(--mine-border);background:var(--accent-surface);color:var(--text);box-shadow:inset 0 0 0 1px var(--mine-border)}
.gform-pill>input:checked+span,.gform-chip>input:checked+span{font-weight:750}
.gform-chip>input:checked+span::before{content:"\2713";content:"\2713" / "";margin-right:7px;font-weight:800}
.gform-pill>input:focus-visible+span,.gform-chip>input:focus-visible+span,.gform-choice>input:focus-visible+span{outline:3px solid var(--focus);outline-offset:2px}
/* The one decision: has the venue said yes. Chosen reads like a chosen appearance, never a second lime. */
.gform-choice{margin:0 0 8px}
.gform-choice>span{display:block;position:relative;padding:13px 14px 13px 46px;border:1px solid var(--line2);border-radius:12px;background:var(--panel);color:var(--text);font-weight:500}
.gform-choice>span::before{content:"";position:absolute;left:14px;top:15px;width:20px;height:20px;box-sizing:border-box;border:2px solid var(--line2);border-radius:50%;background:var(--panel)}
.gform-choice>input:checked+span::before{border-color:var(--text);background:var(--text);box-shadow:inset 0 0 0 4px var(--panel)}
.gform-choice>input:disabled{cursor:not-allowed}
.gform-choice>input:disabled+span{opacity:1}
.gform-choice>input:disabled{opacity:.55}
.gform-choice strong{display:block;font-size:15px;line-height:1.35}
.gform-choice small{display:block;font-size:13px;line-height:1.4;color:var(--detail-text);margin-top:2px}
.gform-override{border-left:3px solid var(--warn);border-radius:0 12px 12px 0;background:var(--maybe-surface);color:var(--text);padding:2px 13px 12px;margin:10px 0 0}
.gform-override .check-label{font-size:14px;font-weight:700;color:var(--text)}
.gform-override .inline-note{margin-top:0;font-size:13px;line-height:1.45;color:var(--detail-text)}
/* Book this date says what booking does to the enquiry, date by date. */
.gform-booking-what{font-size:14px;line-height:1.5;color:var(--text);margin:0;overflow-wrap:anywhere}
.gform-released{list-style:none;display:grid;gap:1px;margin:8px 0 0;padding:0;background:var(--line);border:1px solid var(--line);border-radius:12px;overflow:hidden}
.gform-released>li{display:flex;flex-wrap:wrap;justify-content:space-between;align-items:baseline;gap:2px 12px;background:var(--panel2);padding:10px 13px;font-size:14px;font-weight:650}
.gform-verdict{font-size:13px;font-weight:650}
.gform-verdict.good{color:var(--good)}
.gform-verdict.cover{color:var(--cover)}
.gform-verdict.warn{color:var(--warn)}
.gform-verdict.wait{color:var(--waiting-text)}
.gform-verdict.bad{color:var(--bad)}
.gform-better{border-left:3px solid var(--warn);border-radius:0 12px 12px 0;background:var(--maybe-surface);color:var(--text);font-size:13px;line-height:1.45;padding:9px 13px;margin:10px 0 0}
.gform-booking-undo{font-size:13px;line-height:1.45;color:var(--detail-text);margin:10px 0 0}
/* Last: what is still missing or why the button is off, then the one button, full width. */
.gform-end{margin-top:18px}
.gform-needed,.gform-why{font-size:13px;line-height:1.45;margin:0 0 6px;overflow-wrap:anywhere}
.gform-needed{color:var(--detail-text)}
.gform-why{color:var(--text);font-weight:650}
.gform .gform-offline{margin:0 0 6px}
.gform>.gform-actions{border-top:0;margin-top:6px;padding-top:6px}
.gform>.gform-actions>button{flex:1 1 100%;min-height:50px;font-size:16px}
/* Save's field errors sit under the field they are about. */
.gform-error{font-size:13px;font-weight:650;line-height:1.4;color:var(--bad);margin:6px 0 0}
.gform input[aria-invalid=true],.gform .timefield[aria-invalid=true]{border-color:var(--bad);box-shadow:0 0 0 1px var(--bad)}
@media(max-width:550px){
  .gform-rung>.timefield{flex-basis:128px;width:128px}
  .gform-facts>div{grid-template-columns:118px minmax(0,1fr)}
}
@media(max-width:350px){
  .gform-rung>.timefield{flex-basis:112px;width:112px}
  .gform-pills{grid-template-columns:repeat(3,minmax(0,1fr))}
}

/* h39 · Tapping outside a card closes it, and one scrolling clock sets every time in the app. Existing tokens only
   (--panel, --panel2, --line, --line2, --text, --muted, --accent, --accent-surface, --input-surface), so the Day/Night
   variable guard and the contrast sweep cover this block unchanged, and no text carries opacity. */
/* Without this a backdrop tap can sit behind iOS's 300ms double-tap-zoom wait, which reads as the gesture not working.
   styles.css already sets it on button/a/input/textarea, but not on the sheet itself. */
.action-dialog{touch-action:manipulation}
/* The field shows a time and opens the clock; it is not typed into. Since h43 it is a <button> (see timeInput in
   app.js: iOS opened its own wheel whenever focus came back to an <input type="time">, readonly or not), drawn as
   the time input it replaced — the input box styles.css gives every field, 16px so nothing zooms, the value on the
   left in tabular figures, and the field's own "this opens a chooser" mark on the right, inside the button, so a tap
   on the mark is a tap on the field: one target, one thing that happens. The button's own hover fill is not taken:
   a field does not light up like an action. An empty time shows --:-- in the muted colour, as the native field did. */
.timefield{display:flex;align-items:center;justify-content:space-between;gap:8px;width:100%;min-width:0;min-height:47px;margin:0;padding:11px 14px 11px 12px;border:1px solid var(--line2);border-radius:10px;background:var(--input-surface);color:var(--text);font-size:16px;font-weight:500;line-height:1.45;text-align:left;font-variant-numeric:tabular-nums;cursor:pointer;user-select:none;-webkit-user-select:none}
.timefield:hover{background:var(--input-surface);border-color:var(--line2)}
.timefield:disabled{opacity:.65}
.timefield-value{min-width:0;white-space:nowrap}
.timefield[data-empty] .timefield-value{color:var(--muted)}
.timefield[aria-expanded="true"]{border-color:var(--accent)}
.timefield-mark{flex:none;font-size:13px;line-height:1;color:var(--muted)}
/* The sheet is a layer back while the clock is up: inert, and under the veil — one scrim over the whole viewport,
   which also carries the tap that dismisses the clock. A scrim rather than opacity on .dialog-head and #dialogBody:
   the head is sticky over its own content, so making it translucent lets the form scroll visibly through it. The
   literal follows .action-dialog::backdrop in styles.css, which is the same kind of decision. */
/* A modal sheet is in the top layer, above #toast and above every z-index in the page, so anything said to someone
   looking at a sheet is said in the sheet. The head is sticky, so the line is on screen however far the sheet is
   scrolled — unlike #dialogError, which sits after #dialogBody and is below the fold on a tall sheet. It is a note
   in the head's own grid, on the row under the title, like .dialog-back above it. */
.dialog-note{grid-column:1/-1;margin:2px 0 8px;padding:9px 12px;font-size:13px;line-height:1.35;color:var(--notes-text);background:var(--panel2);border:1px solid var(--line2);border-radius:10px;overflow-wrap:anywhere}
.twheel-veil{position:fixed;inset:0;z-index:6;background:#0006}
/* Pinned to the bottom inside edge of the sheet at every width: sticky is what beta.css already endorses for this
   scroller, and it means a sheet that is already scrolled needs no arithmetic. margin-top:auto covers the short sheet
   the min-height floor creates; being in flow, the tray also lengthens the scroll, so the last field still clears it. */
.twheel{position:sticky;bottom:0;z-index:7;margin-top:18px;padding:12px 14px calc(12px + env(safe-area-inset-bottom));background:var(--panel2);border:1px solid var(--line2);border-radius:14px}
.twheel-head{display:flex;align-items:baseline;justify-content:space-between;gap:10px;min-height:22px}
.twheel-head .section-label{margin:0}
.twheel-now{font-size:15px;font-weight:750;font-variant-numeric:tabular-nums;color:var(--text)}
.twheel.pending .twheel-now{font-weight:600;color:var(--muted)}
.twheel-body{position:relative;display:flex;align-items:stretch;justify-content:center;gap:4px;margin:8px 0 4px}
/* 220px of column is five 44px rows; 88px of padding at each end is two more, so the first and last value can still
   reach the middle. The band must agree with that arithmetic or the chosen row sits off centre: row i is at
   88 + 44i, the column shows 220, so centring it is scrollTop = 44i and the band sits at top:88px, height 44px. */
.twheel-band{position:absolute;left:6px;right:6px;top:88px;height:44px;background:var(--accent-surface);border-top:1px solid var(--line2);border-bottom:1px solid var(--line2);pointer-events:none;z-index:0}
.twheel.pending .twheel-band{background:transparent;border:1px dashed var(--line2)}
.twheel-col{position:relative;z-index:1;width:96px;height:220px;overflow-y:scroll;scroll-snap-type:y mandatory;overscroll-behavior:contain;touch-action:pan-y;scrollbar-width:none}
.twheel-col::-webkit-scrollbar{display:none}
/* h39 review · Chrome matches :focus-visible on a programmatic focus that followed a touch, so opening the clock
   with a finger painted a 3px lime frame round the hour column — louder than the band, which is the thing that
   actually says which number is chosen — and a finger's Set left one round the field. data-quiet-focus is the
   one-shot the app sets on those pointer paths only; the first key clears it, so every keyboard ring is untouched.
   var(--focus) rather than var(--accent), which is what every other focus ring in the app uses in both themes. */
.twheel-col:focus-visible{outline:3px solid var(--focus);outline-offset:-3px;border-radius:11px}
.twheel-col[data-quiet-focus]:focus-visible,.timefield[data-quiet-focus]:focus-visible{outline:none}
.twheel-pad{height:88px}
.twheel-item{height:44px;display:grid;place-items:center;scroll-snap-align:center;font-size:21px;font-weight:650;font-variant-numeric:tabular-nums;color:var(--muted);cursor:pointer}
.twheel-item.on{color:var(--text);font-weight:800}
.twheel-colon{position:relative;z-index:1;align-self:center;font-size:21px;font-weight:800;color:var(--text)}
/* h43 · Steve: Clear "needs to be a button with a centered label". Two real buttons, side by side and the same
   size: Clear the quiet one — the sheet's own panel colour inside the tray, a full-strength outline and the text
   colour, so it reads as a button in Day and Night without competing with the lime — and Set the lime primary. Each
   takes half the foot, 48px tall, with its label centred both ways. */
.twheel-foot{display:grid;grid-template-columns:1fr 1fr;gap:10px;padding-top:8px}
.twheel-foot button{display:flex;align-items:center;justify-content:center;min-width:0;min-height:48px;margin:0;padding:10px 14px;font-size:16px;font-weight:750;line-height:1.2;text-align:center}
.twheel-foot .secondary{background:var(--panel);border-color:var(--line2);color:var(--text)}
.twheel-foot .secondary:hover{background:var(--hover);border-color:var(--muted)}
/* h39 review · Under 550px .action-dialog is the bottom sheet, and it already carries the home indicator's inset in
   its own padding-bottom; a sticky tray is clamped by that padding, so it can never reach the indicator and its own
   inset is counted a second time — a 34px dead strip under Set on the iPhone, and 34px taken off the dials on the
   narrowest screen in the band. Only here: above 550px the sheet is an ordinary block, the tray really does pin to
   the scrollport, and its inset is the only thing keeping Clear and Set off an iPad's indicator. */
@media(max-width:550px){
  .twheel{margin-top:auto;padding-bottom:12px}
}
/* h39 review · A phone on its side is 375px tall: the sheet is capped at 100dvh - 24px = 351px and a 330px tray
   covers all of it — the head, the ×, and the very field being set. Three visible rows instead of five brings the
   tray to ~242px, which leaves the head and the field clear and gives openTimeWheel's scroll room to work. Every
   number the clock counts on is kept: rows stay 44px, the pad is (column - 44)/2 so row i still sits at 44 + 44i,
   centring row i is still scrollTop = 44i, and the band still starts one row down. */
@media(max-height:520px){
  .twheel-col{height:132px}
  .twheel-pad{height:44px}
  .twheel-band{top:44px}
  /* Even at 242px the tray leaves only 12px between the sticky head and itself, and a time field is 51px: sideways
     there is no scroll position where the field clears both. The head is inert while the clock is up — the × cannot
     be used, and the tray's own head names the time being set — so it gives up its pin and scrolls with the sheet,
     which leaves the whole 88px above the tray for the field. It sticks again the moment the clock closes. */
  .action-dialog.wheel-open .dialog-head{position:static}
}
@media(max-width:350px){
  .twheel-col{width:84px}
}
/* h41 · Me: Sign out on its own at the foot of the page, and the My icon picker. Existing tokens only (--line,
   --panel2, --text, --muted, --accent, --accent-surface), so the Day/Night variable guard and the contrast sweep cover
   this block unchanged. Tiles are 44px targets and more; the page still has no lime button (Sign out is secondary). */
.me-signout{margin-top:28px;padding-top:20px;border-top:1px solid var(--line)}
.me-signout>button{min-height:48px}
.role-icon-intro{margin:0 0 14px}
.role-icon-stale{margin:0 0 14px}
.role-icon-search{margin:0 0 14px}
.role-icon-group{margin-top:18px}
.role-icon-group>.section-label{margin:0 0 8px}
.role-icon-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(72px,1fr));gap:6px}
.role-icon-tile{position:relative;display:flex;flex-direction:column;align-items:center;justify-content:flex-start;gap:6px;min-height:44px;padding:10px 2px 8px;border:1px solid var(--line);border-radius:12px;background:var(--panel2);color:var(--text);font-weight:600}
.role-icon-tile .member-mark.identity{width:48px;height:48px}
/* Measured at 375pt: every catalogued word fits a tile's width, Photographer by its soft hyphen (tools/role-icons.mjs).
   A name from a slug Steve adds later may not, so hyphenation, then any break, is the last resort. */
.role-icon-tile{min-width:0}
.role-icon-name{font-size:12px;line-height:1.25;text-align:center;-webkit-hyphens:auto;hyphens:auto;overflow-wrap:anywhere}
/* The icon in use: the accent border and a tick, said once and in the tile's own label for a screen reader. */
.role-icon-tile.chosen{border:2px solid var(--accent);background:var(--accent-surface);padding:9px 1px 7px}
.role-icon-tick{position:absolute;top:4px;right:7px;font-size:13px;line-height:1;font-weight:800;color:var(--accent)}
.role-icon-note{margin-top:14px}
/* h42 · D12 · Joining the band. The join card is the sign-in card's twin: same surface, one stage at a time, one lime
   button per stage, text buttons for the ways out. Band access gains the people asking to join, the join code and a
   line per place, in the sheet's existing grammar. Existing tokens only, so Day and Night follow by themselves. */
.join-entry{display:block;margin:0;color:var(--text);font-weight:650}
.signed-in-here .join-entry{display:none}
.join-brand{font-size:32px;font-weight:800;letter-spacing:-1px}
.join-title{font-size:22px;letter-spacing:-.5px;text-align:center;margin:0 0 8px}
.join-intro{color:var(--muted);font-size:14px;line-height:1.5;text-align:center;margin:0 0 20px;overflow-wrap:anywhere}
.join-intro .nowrap{white-space:nowrap}
.join-form{display:grid}
.join-form .primary{margin-top:4px}
.join-steps{margin:0 0 16px;padding-left:22px;display:grid;gap:8px;font-size:14px;line-height:1.45;color:var(--detail-text)}
.join-code{font-size:30px;font-weight:800;letter-spacing:.12em;text-align:center;font-variant-numeric:tabular-nums;margin:6px 0 8px;-webkit-user-select:all;user-select:all;overflow-wrap:anywhere}
.join-card .inline-note{margin:0 0 16px;text-align:center}
.join-card .join-message:empty{display:none}
.join-alt{margin-top:10px}
.join-places{border:0;padding:0;margin:0 0 16px;display:grid;gap:8px;min-width:0}
.join-place{display:grid;grid-template-columns:auto auto 1fr;align-items:center;gap:10px;margin:0;padding:10px 12px;border:1px solid var(--line);border-radius:14px;background:var(--panel2);color:var(--text);font-size:15px;font-weight:650;cursor:pointer}
.join-place input{width:20px;height:20px;min-height:0;margin:0;padding:0;accent-color:var(--accent)}
.join-place:has(input:checked){border-color:var(--accent);background:var(--accent-surface)}
.join-place.barred{cursor:not-allowed;opacity:.75}
.join-place-name{display:grid;gap:2px;min-width:0}
.join-place-name small{color:var(--muted);font-size:12px;font-weight:500;line-height:1.4}
.acc-section{display:grid;gap:10px;margin:0 0 22px}
.acc-section .section-label{margin:0}
.acc-request{display:grid;gap:6px;padding:12px;border:1px solid var(--line);border-radius:14px;background:var(--panel2)}
.acc-request .sub-actions{margin-top:4px}
.acc-request-head{margin:0;font-size:15px;overflow-wrap:anywhere}
.acc-meta{margin:0;color:var(--muted);font-size:12px}
.acc-warn{margin:0;color:var(--warn);font-size:13px;line-height:1.45}
.acc-place{display:grid;gap:4px;padding:10px 0;border-top:1px solid var(--line)}
.acc-place-head{display:grid;grid-template-columns:auto 1fr auto;align-items:center;gap:10px}
.acc-who{margin:0;display:grid;gap:2px;min-width:0}
.acc-state{color:var(--muted);font-size:12px;overflow-wrap:anywhere}
.acc-release{color:var(--bad)}
.acc-edit summary{display:flex;align-items:center;min-height:44px;color:var(--muted);font-size:13px;cursor:pointer}
.acc-place .access-row{margin-bottom:6px}
.acc-earlier{margin:6px 0;color:var(--muted);font-size:12px;overflow-wrap:anywhere}
.acc-section .inline-note{margin:0}
.acc-section .sub-actions{margin-top:0}
/* h43 · Change my icon (Me) and Manage access (Band) are controls at rest, not text that only answers a hover a phone
   has not got. Each is a secondary button (its outline and fill) sized for a thumb, 44px and more, with the quiet row's
   chevron for "opens a sheet". The chevron is generated content with empty alternative text, so each button's name is
   exactly its words. button.sheet-button outranks .sub-actions button's 12px. Existing tokens only (--text, --muted),
   so Day and Night follow by themselves. Manage access starts at the page's left edge (styles.css .manage-access). */
button.sheet-button{display:inline-flex;align-items:center;gap:8px;min-height:44px;padding:10px 12px 10px 14px;border-radius:11px;font-size:14px;line-height:1.2;color:var(--text);text-align:left}
button.sheet-button::after{content:"\203A";content:"\203A" / "";color:var(--muted);font-size:19px;font-weight:400;line-height:1}
/* On Band it sits under Venue Book and Beta feedback, so it takes their type size, as a sibling rather than a louder one. */
.manage-access>button.sheet-button{font-size:12px}
.manage-access>button.sheet-button::after{font-size:17px}
/* h43 · The confirmation card (confirmCard in app.js): GigLock's own popup in place of the browser's confirm(). A small
   card centred over the sheet's own dimmed backdrop, at every width: it asks one question, so it is never the bottom
   sheet. The question is its heading and what it costs sits under it; then the ranked action (lime, or the danger
   style when the answer loses something) above the way out, each a full-width 48px target. Existing tokens and button
   classes only, so Day and Night follow by themselves and the contrast sweep covers this block unchanged. */
.confirm-card{width:min(360px,calc(100% - 32px));max-height:calc(100dvh - 32px);margin:auto;padding:26px 22px 20px;overflow:auto;overscroll-behavior:contain;border:1px solid var(--line2);border-radius:21px;background:var(--panel);color:var(--text);box-shadow:0 20px 100px #0009;text-align:center;touch-action:manipulation}
.confirm-card::backdrop{background:#000b;backdrop-filter:blur(3px)}
/* h43 D24 · Balanced lines, so a question or its cost never ends on one stranded word ("Colin.", "lost.") at 390px. */
.confirm-title{font-size:19px;line-height:1.3;letter-spacing:-.3px;overflow-wrap:anywhere;text-wrap:balance}
.confirm-message{margin-top:10px;font-size:14px;line-height:1.5;color:var(--detail-text);overflow-wrap:anywhere;text-wrap:balance}
.confirm-actions{display:grid;gap:10px;margin-top:22px}
.confirm-actions>button{width:100%;min-height:48px;font-size:15px}
/* D39 · The band's name and logo (docs/BAND_IDENTITY_DESIGN.md). In the header the brand shrinks and only the name gives
   way, ending in "…", so the bell and Me always fit at 320px, with "GigLock" small above it. A logo sits on its own
   plate, light or dark in Day and Night alike because it is the logo's background, not the app's, and never in
   .member-mark, which crops, enlarges and tints. Without the band's identity the header keeps h46's markup, and
   nothing here matches it. The preview strips in the sheet draw the phone header in fixed Night and Day colours
   (styles.css :root and :root[data-appearance="day"]), whichever the app is in. */
.brand.band-brand{min-width:0;flex:0 1 auto;gap:9px}
.band-brand~.account-area{flex:none}
.band-pic,.band-card-pic{flex:none;display:flex}
.band-plate{display:grid;place-items:center;flex:none;width:37px;height:37px;padding:3px;border-radius:9px}
.band-plate.light{background:#f7f8f4;box-shadow:inset 0 0 0 1px #0000001f}
.band-plate.dark{background:#15191e;box-shadow:inset 0 0 0 1px #ffffff29}
.band-plate img,.brand .band-plate img{display:block;width:100%;height:100%;object-fit:contain;border-radius:0}
.brand-text{display:flex;flex-direction:column;min-width:0;line-height:1.1}
/* Steve, 28 Sep: GigLock's own line, its mark and name side by side and centred across the top of the bar, above the
   band's row ("Own line at the top"). The bar becomes a two-row grid and grows by the line; nothing else sticks to the
   top of the page, so nothing slides under it. A grid, not a wrapping flex row: the band's row must never wrap (on a
   320 px phone the bell and Me would drop to a third row); its first column shrinks and the name ends in "…" as
   before. .brand's narrow-screen padding-top belonged to the old one-row bar. */
.topbar.has-giglock-line{display:grid;grid-template-columns:minmax(0,1fr) auto;row-gap:2px;align-items:center;padding-top:6px;padding-bottom:8px}
.topbar.has-giglock-line .giglock-line{grid-column:1/-1}
.topbar.has-giglock-line .brand{padding-top:0;justify-self:start;max-width:100%}
.giglock-line{display:flex;align-items:center;justify-content:center;gap:6px;height:20px;font-size:13px;font-weight:750;letter-spacing:.02em;line-height:1;color:var(--muted);white-space:nowrap}
.giglock-line img{flex:none;display:block;width:18px;height:18px}
.band-pic:empty{display:none}
.band-brand .brand-name{font-size:22px;letter-spacing:-.5px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.band-identity-card{margin:0 0 16px}
.band-identity-head{display:flex;align-items:center;gap:14px;min-width:0}
.band-identity-head h1{font-size:22px;line-height:1.2;margin:0;min-width:0;overflow-wrap:anywhere}
.band-card-pic .band-plate{width:64px;height:64px;padding:5px;border-radius:14px}
.band-identity-card .sub-actions{margin-top:10px}
/* The strips are the header of a 320px phone, the narrowest it is built for, at its own sizes there (a 30px plate or
   mark 9px from the name; the 36px bell and 42px Me, 4px apart and 4px from the brand; 12px in from each edge), so a
   name ends in "…" in the preview exactly when it does in that header. Where the sheet is narrower than 320px (on a
   320px phone), the strip is zoomed down whole, never laid out narrower. */
.band-preview{display:grid;gap:8px;margin:0 0 18px;container-type:inline-size}
.band-strip{border-radius:12px;padding:7px 0 0;overflow:hidden}
.band-strip.night{background:#0b0d10;color:#f4f6f8;box-shadow:inset 0 0 0 1px #2b323a}
.band-strip.day{background:#f2f4ef;color:#242c24;box-shadow:inset 0 0 0 1px #cdd5c8}
.band-strip-label{display:block;padding:0 12px;font-size:10px;font-weight:700;letter-spacing:.07em;text-transform:uppercase}
.band-strip-bar{display:flex;align-items:center;justify-content:space-between;gap:4px;width:320px;height:58px;padding:0 12px}
.band-strip .brand{color:inherit;font-size:19px}
.band-strip .band-brand .brand-name{font-size:18px}
/* The small lines are painted on the strip's own colour, said here too so the contrast sweep measures the real pair. */
.band-strip.night .giglock-line,.band-strip.night .band-strip-label{color:#a3adb8;background:#0b0d10}
.band-strip.day .giglock-line,.band-strip.day .band-strip-label{color:#586354;background:#f2f4ef}
/* GigLock's line in the preview, centred over the 320 px bar it sits on, and zoomed with it on a narrower sheet. */
.band-strip .giglock-line{width:320px;margin:4px 0 -4px}
.band-strip .band-brand .band-plate,.band-strip .band-pic>img{width:30px;height:30px}
.band-strip-tools{display:flex;align-items:center;gap:4px;flex:none}
.band-strip-tools span{width:36px;height:36px;border-radius:50%;border:1px solid currentColor;opacity:.3}
.band-strip-tools span+span{width:42px;height:42px}
@container (max-width:319.98px){.band-strip-bar{zoom:.9375}}
@container (max-width:299.98px){.band-strip-bar{zoom:.875}}
@container (max-width:279.98px){.band-strip-bar{zoom:.8125}}
@container (max-width:259.98px){.band-strip-bar{zoom:.75}}
@container (max-width:319.98px){.band-strip .giglock-line{zoom:.9375}}
@container (max-width:299.98px){.band-strip .giglock-line{zoom:.875}}
@container (max-width:279.98px){.band-strip .giglock-line{zoom:.8125}}
@container (max-width:259.98px){.band-strip .giglock-line{zoom:.75}}
.band-logo-actions{display:flex;flex-wrap:wrap;gap:10px}
label.band-file{display:inline-flex;align-items:center;min-height:44px;margin:0;padding:10px 15px;border:1px solid var(--line);border-radius:11px;background:var(--panel2);color:var(--text);font-size:15px;font-weight:650;cursor:pointer}
label.band-file:hover{border-color:var(--line2);background:var(--hover)}
#bandIdentityForm:has(#bandLogoFile:focus-visible) label.band-file{outline:3px solid var(--focus);outline-offset:2px}
.band-plate-choice{margin-top:14px}
.band-plate-choice .section-label{margin:0 0 6px}
.band-plate-pills{display:grid;grid-template-columns:repeat(2,minmax(0,112px));gap:6px}
@media(max-width:600px){.band-brand .brand-name{font-size:18px}.giglock-line{font-size:12px}}
@media(max-width:550px){.band-brand .band-plate{width:34px;height:34px}}
@media(max-width:350px){.band-brand .band-plate{width:30px;height:30px}}
/* h43 · My icon is a card, not a sheet. Steve: "The My icon popup card should not be attached to the bottom of the app
   on Mac or iPhone." openDialog marks the one dialog that asks for it (context.presentation 'card') with .centred-card
   and nothing else changes: every other sheet is still a bottom sheet on a phone. Two classes outrank every
   .action-dialog rule above, whatever its media query, so this one block undoes the bottom sheet's margins, square
   corners, 70dvh floor and home-indicator padding for this card alone.
   · Centred both ways at every width: margin:auto inside the fixed box a modal dialog is given. The box ends above the
     keyboard, so the keyboard the search brings up lifts and shrinks the card rather than covering it.
   · Even margins: the same gap either side on each axis, never under 16px and never under the larger safe-area inset
     on that axis (the notch, the Dynamic Island, the home indicator), so it is centred on the screen and clear of
     all of them. A taller window gives it a little more air, up to 56px, and a large screen a card of at most 780px.
     While a keyboard is up that air, and the home indicator's clearance (the indicator is behind the keys then), go
     back to the card: --card-air is 56px with no keyboard and 0 once one is showing, so a phone on its side keeps
     16px above and below and gives the rest to the search and the grid.
   · A head that never moves and a body that scrolls: the card is a column, the head across the top over a hairline,
     and #dialogBody the one scroller under it, so the scroll bar starts below the hairline and stays inside the
     rounded corners. The page behind is locked (lockPage) and overscroll stays in the card.
   · How tall: with the search (a catalogue long enough to need one) the card is as tall as it may be, whatever the
     search leaves in it, so typing never moves the card, the field or the ×, and the results fill from the top.
     Without it (no icons yet), the card is only as tall as what it holds, and still centred.
   Existing tokens only, so the Day/Night variable guard and the contrast sweep cover it unchanged. */
.action-dialog.centred-card{
  --card-air:max(0px,calc(56px - var(--keyboard-inset,0px)));
  --card-gap-x:max(16px,env(safe-area-inset-left),env(safe-area-inset-right));
  --card-gap-y:max(16px,min(6dvh,var(--card-air)),env(safe-area-inset-top),min(env(safe-area-inset-bottom),var(--card-air)));
  --card-height:min(780px,calc(100dvh - var(--keyboard-inset,0px) - 2*var(--card-gap-y)));
  inset:0 0 var(--keyboard-inset,0px);margin:auto;
  width:min(480px,calc(100% - 2*var(--card-gap-x)));max-width:none;
  min-height:0;max-height:var(--card-height);
  display:flex;flex-direction:column;overflow:hidden;
  border-radius:22px;padding:0
}
.action-dialog.centred-card:not([open]){display:none}
.action-dialog.centred-card:has(#roleIconSearch){height:var(--card-height)}
.action-dialog.centred-card .dialog-head{flex:0 0 auto;margin:0;padding:10px 10px 10px 20px;border-bottom:1px solid var(--line)}
.action-dialog.centred-card .dialog-head h2{font-size:20px}
/* Steve, 28 Sep, on his iPhone: the green ring around the card's × "seems to fall off the edge of the viewable screen".
   The card opens with the × focused, and the focus ring (3px wide, 3px outside the button) reached past the card's
   edge, 4px from the × on a phone, where the card clips it (overflow:hidden). The card's × draws its ring just inside
   its own edge instead: the same ring, never cut, upright or sideways. (A bottom sheet's × has the sheet's padding
   around it, so its ring was never cut.) */
.action-dialog.centred-card .dialog-head .icon-button:focus-visible{outline-offset:-3px}
/* --keyboard-room is the end-of-form room every sheet gets while a keyboard is up (#dialogBody, above); the card's own
   padding would otherwise replace it. */
.action-dialog.centred-card #dialogBody{flex:1 1 auto;min-height:0;overflow:auto;overscroll-behavior:contain;padding:16px 20px calc(20px + var(--keyboard-room,0px))}
.action-dialog.centred-card #dialogError{flex:0 0 auto;margin:0 20px 16px}
/* A tile narrower than 76px breaks Microphone, Tambourine and Megaphone mid-word (measured, 12px names), so the card's
   grid never goes under it: where four do not fit, it takes three. On a phone the card gives its width to the grid,
   12px inside and a 4px gap, which keeps four a row from 375pt up — as the sheet had — with even gutters outside. */
.action-dialog.centred-card .role-icon-grid{grid-template-columns:repeat(auto-fill,minmax(76px,1fr))}
@media(max-width:550px){
  .action-dialog.centred-card .dialog-head{padding:8px 4px 8px 12px}
  .action-dialog.centred-card #dialogBody{padding:14px 12px calc(12px + var(--keyboard-room,0px))}
  .action-dialog.centred-card #dialogError{margin:0 12px 12px}
  .action-dialog.centred-card .role-icon-grid{gap:4px}
}
/* A phone on its side: the head gives up its air above and below the 44px ×, and the body its first 6px, which is the
   room a keyboard leaves for the search and a row of results. */
@media(max-height:520px){
  .action-dialog.centred-card .dialog-head{padding-top:2px;padding-bottom:2px}
  .action-dialog.centred-card #dialogBody{padding-top:10px}
}
