/* --------------------------------------------------------------------------
   Year stream

   The destination for "Concert & Event Photos": a scrollable year of full
   640px frames rather than a grid of 240x160 crops. Loaded by the year pages
   at /galleries/<year>/, by the individual gallery pages beneath them, and by
   the home page, all of which share the same chrome.

   Layered on top of css/site.css, which supplies the palette and the base page
   chrome. Where this file restyles shared chrome -- the header bar and the
   social icons -- it only reaches pages that opt in by linking it.
   -------------------------------------------------------------------------- */

/* The frame width every band of the page shares: two 640px photographs plus
   the gutter between them. Anything full-bleed against the browser edge reads
   as detached from the content once the grid is centred.

   1308 = 640 + 28 + 640, and nothing else: the page margin comes from body's
   own 12px padding rather than being added again here. That matters at the
   threshold -- with 16px of padding of its own, the grid needed 1379px of
   window before it could show two columns, which put a 1366px laptop into a
   single column for the sake of 32 pixels it did not need. */
.stream,
.streamBar {
	max-width: 1308px;
	margin: 0 auto;
}

/* The year sits close above the first row, so it reads as the head of the
   stream rather than as a separate band of chrome. */
.stream {
	padding: 17px 0 10px;
}

.streamBar {
	padding: 0;
	box-sizing: border-box;
}

/* --------------------------------------------------------------------------
   Sticky chrome

   Two bands pin to the top of the window as the page scrolls: the utility bar
   carrying Home and the social links, and below it the year. Neither is worth
   scrolling back up for, and on a year of eighty shows that is a long way
   back.

   Neither band is allowed to read as a darker stripe across the page. The
   utility bar is painted in the page's own colour, so at rest it is simply
   invisible and the masthead disappears cleanly behind it on the way up. Once
   the chrome is carrying content over photographs it goes translucent -- still
   the page colour, just thinned, with a blur behind it -- so the pictures
   visibly pass underneath rather than stopping at a hard edge.
   -------------------------------------------------------------------------- */

:root {
	--dc-topbar-h: 52px;
	/* One row of the year picker. Tall enough to hold the year at the size the
	   label carries it, so the row that opens over the label is the same shape
	   as the label. */
	--dc-yearrow: 34px;
	/* How far the caption hangs below the photograph, and the shortest it is
	   allowed to be. Between them these decide how much of the image the panel
	   covers: min-height minus drop is what sits on the photograph, and that
	   has to stay above the ~38px the wordmark occupies. The minimum matters
	   because captions with no venue are a line shorter, and a panel anchored
	   below the frame would otherwise ride up and expose the mark. */
	--cap-drop: 16px;
	--cap-min: 64px;
	/* And how far it sits in from the right edge, so it reads as a card resting
	   on the photograph rather than something welded to the corner. There is
	   not much room to play with: measured at 6x zoom on frames from 2018,
	   2019 and 2020, the wordmark ends a consistent 8.5-9px from the right
	   edge of a 640px frame -- 1.37% of its width. The inset is a percentage
	   rather than a length so that margin holds at every frame size; a fixed
	   6px would have eaten all of it by the time the frame reached 400px. At
	   640 this works out to about 5.8px. */
	--cap-inset: 0.9%;
}

/* The utility bar is pinned from the first frame -- it starts where it used to
   end up after scrolling, and never moves. It carries no fill until it
   collapses: an opaque bar would swallow the masthead 50px before the masthead
   reached the top of the window, and the bar's middle is empty until the
   collapsed name arrives there anyway. */
body {
	padding-top: 0;
}

.streamTopBar {
	position: sticky;
	top: 0;
	z-index: 40;
	background-color: transparent;
	border-bottom: 1px solid rgba(255, 255, 255, 0);
	transition: border-color 240ms ease, background-color 240ms ease;
}

/* Collapsed, the bar frosts whatever is passing beneath it. But only while it
   is alone: once the year bar pins directly below, the two rows have to read
   as one surface, and two stacked translucent bars cannot do that. Each one
   blurs its own backdrop, so they sample different content and the join
   between them shows up as a hard line with a mismatched band underneath.
   The handover is below -- the year bar grows a single pane tall enough to
   cover both rows, and this one gets out of its way. */
.streamTopBar.is-collapsed {
	background-color: rgba(42, 42, 42, 0.78);
	backdrop-filter: blur(16px) saturate(140%);
	-webkit-backdrop-filter: blur(16px) saturate(140%);
	border-bottom-color: rgba(255, 255, 255, 0.07);
}

.streamTopBar.is-collapsed:has(~ .yearBar.is-stuck) {
	background-color: transparent;
	backdrop-filter: none;
	-webkit-backdrop-filter: none;
	border-bottom-color: transparent;
}

.topBarInner {
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: 16px;
	min-height: var(--dc-topbar-h);
}

/* The masthead in one line. It stays out of the bar until the full masthead
   has scrolled past, at which point it takes over the identity so the bar is
   never just two anonymous controls. */
/* Matched to the year label, so the collapsed bar reads at the same weight as
   the control beneath it rather than as a caption. */
.brandCompact {
	flex: 1 1 auto;
	min-width: 0;
	text-align: center;
	font-family: var(--dc-font-display);
	font-size: 19px;
	letter-spacing: 2.2px;
	white-space: nowrap;
	overflow: hidden;
	text-overflow: ellipsis;
	color: #a6a6a6;
	opacity: 0;
	transform: translateY(6px);
	transition: opacity 260ms ease, transform 260ms ease;
	pointer-events: none;
}

.streamTopBar.is-collapsed .brandCompact {
	opacity: 1;
	transform: none;
}

.brandCompactName {
	color: var(--dc-fg, #f2f2f2);
}

.brandCompactPlace::before {
	content: "|";
	padding: 0 7px;
	color: #6f6f6f;
}

@media (max-width: 620px) {
	.brandCompact {
		display: none;
	}
}

/* --------------------------------------------------------------------------
   Masthead

   Sits lower than the utility bar rather than crowding it. The name carries
   the block: the line above and the line below are supporting detail, so they
   sit a step back in contrast rather than competing at full strength.
   -------------------------------------------------------------------------- */

.streamHeader {
	/* Halved twice from the original 22px. The masthead sits just under the
	   icon row; the buffer below it is what separates it from the year, and
	   that one is deliberately larger. */
	padding-top: 6px;
	padding-bottom: 17px;
	transition: opacity 200ms ease;
}

/* The compact name and the full masthead are the same thing in two sizes, so
   only one of them is ever on screen: as the bar takes the name over, what is
   left of the masthead behind it clears out rather than doubling up. */
.streamTopBar.is-collapsed ~ .streamHeader {
	opacity: 0;
}

.streamHeader .headerTextPre,
.streamHeader .headerTextSub {
	color: #a6a6a6;
}

.streamHeader .headerTextMain {
	color: var(--dc-fg, #f2f2f2);
}

/* Mailto that does not announce itself. It is plainly part of the sentence
   until the pointer reaches it, at which point it behaves like a link. */
.quietLink {
	color: inherit;
	text-decoration: none;
}

.quietLink:hover,
.quietLink:focus-visible {
	color: var(--dc-fg, #ffffff);
	text-decoration: underline;
}

.streamFooter {
	color: #8a8a8a;
	letter-spacing: 0.9px;
	padding-top: 30px;
}

/* --------------------------------------------------------------------------
   Home and social icons

   Was five PNGs on coloured tiles, plus a "Home" text link that matched none
   of them. Now one set: a Fluent home glyph on the left and Instagram, X,
   Facebook and mail on the right, all inline SVG drawn in currentColor, all
   the same resting grey. They sit quietly in the bar and only declare
   themselves -- brand colour, or a filled counterpart of the same glyph -- on
   hover.
   -------------------------------------------------------------------------- */

.streamSocial {
	display: flex;
	align-items: center;
	justify-content: flex-end;
	gap: 16px;
}

.streamHome {
	justify-content: flex-start;
	gap: 11px;
}

.streamSocial .socialLink {
	display: inline-flex;
	align-items: center;
	color: #8a8a8a;
	line-height: 0;
	border: 0;
	transition: color 180ms ease, transform 180ms ease;
}

.streamSocial .socialLink:hover,
.streamSocial .socialLink:focus-visible {
	transform: translateY(-1px);
}

.streamSocial .socialInstagram:hover,
.streamSocial .socialInstagram:focus-visible {
	color: #e4405f;
}

/* The X mark is black, which is invisible here, so it goes to full white. */
.streamSocial .socialX:hover,
.streamSocial .socialX:focus-visible,
.streamSocial .socialHome:hover,
.streamSocial .socialHome:focus-visible {
	color: #ffffff;
}

.streamSocial .socialFacebook:hover,
.streamSocial .socialFacebook:focus-visible {
	color: #1877f2;
}

.streamSocial .socialMail:hover,
.streamSocial .socialMail:focus-visible {
	color: #4d9fff;
}

.streamSocial .socialLink:focus-visible {
	outline: 2px solid #0066ff;
	outline-offset: 4px;
	border-radius: 3px;
}

/* Home and mail each ship a regular and a filled cut of the same glyph, and
   swap between them on hover; the brand marks are solid shapes already, so for
   those the colour shift is the whole tell. */
.streamSocial .socialLink .iconFilled {
	display: none;
}

.streamSocial .socialLink:hover .iconRegular,
.streamSocial .socialLink:focus-visible .iconRegular {
	display: none;
}

.streamSocial .socialLink:hover .iconFilled,
.streamSocial .socialLink:focus-visible .iconFilled {
	display: inline;
}

/* --------------------------------------------------------------------------
   Section title and year navigation

   Was four stacked lines -- title, "View: Festivals | By Date", the year, then
   the adjacent years spelled out as links. That is more furniture than a page
   of photographs needs. What is left states the section, states the year, and
   offers a direction.

   The year then pins below the utility bar, so it stays answerable at any
   scroll depth: on a page this long "which year am I in" is a real question.
   -------------------------------------------------------------------------- */

/* --------------------------------------------------------------------------
   The year

   Was four stacked lines -- a section title, "View: Festivals | By Date", the
   year, then the adjacent years spelled out as links. That is more furniture
   than a page of photographs needs, and the title said nothing the photographs
   were not already saying. What is left states the year and offers a
   direction.

   It then pins below the utility bar, so it stays answerable at any scroll
   depth: on a page this long "which year am I in" is a real question.
   -------------------------------------------------------------------------- */

.yearBar {
	position: sticky;
	top: var(--dc-topbar-h);
	z-index: 30;
	padding: 6px 0;
	background-color: rgba(42, 42, 42, 0);
	/* Reserved so the hairline arriving on pin does not shift the row. */
	border-bottom: 1px solid transparent;
	transition: background-color 240ms ease, border-color 240ms ease, padding 240ms ease;
}

/* Only once it is actually pinned does it need to separate itself from the
   photographs passing beneath. Before that it is just a line on the page.
   Pinned, it also steps down a size: it has stopped being the thing you are
   looking at and become a marker, and the height it gives back goes to the
   photographs. */
/* Stuck, the year bar stops painting its own background and instead puts up a
   single pane that reaches back up over the top bar, so both rows are frosted
   by one filter sampling one backdrop. That is the only way the two match:
   glass cannot be tiled. The pane sits behind the bar's own content but inside
   its stacking context, so the year still reads over it, and the top bar --
   transparent by then -- lets it show through from above.

   It carries the hairline too, at the bottom of the pair rather than between
   them. */
.yearBar.is-stuck::before {
	content: "";
	position: absolute;
	inset: calc(-1 * var(--dc-topbar-h)) 0 0 0;
	z-index: -1;
	background-color: rgba(42, 42, 42, 0.78);
	backdrop-filter: blur(16px) saturate(140%);
	-webkit-backdrop-filter: blur(16px) saturate(140%);
	border-bottom: 1px solid rgba(255, 255, 255, 0.07);
}

.yearBar.is-stuck {
	padding: 6px 0;
}

/* The top bar collapses a little before the year bar pins, so it keeps its own
   hairline for that stretch and gives it up once the two become one surface. */
.streamTopBar.is-collapsed:has(~ .yearBar.is-stuck) {
	border-bottom-color: transparent;
}

.yearNav {
	display: flex;
	align-items: center;
	justify-content: center;
	gap: 10px;
	/* The year pages size this row from their 30px stepper buttons. The index
	   and /you/ have no steppers, only a static label, so their bar came out
	   13px shorter and the first row of photographs crowded the heading.
	   Reserving the stepper's height keeps every stream bar the same. */
	min-height: 30px;
}

.yearLabel {
	min-width: 66px;
	font-size: 19px;
	letter-spacing: 3px;
	color: #a6a6a6;
	transition: font-size 240ms ease, letter-spacing 240ms ease, color 180ms ease;
}

/* A year page's heading is the year itself, so the year carries the <h1>
   rather than a second copy of it being hidden somewhere off-screen. The
   element exists only to hold the tag: it takes no size of its own, and the
   year link keeps the identical box the picker measures when it places the
   menu against it. The rest of the heading -- "Concert & Event Photos" -- is
   read but not drawn, because the bar already sits under a masthead that says
   so and repeating it would only crowd the photographs. */
.yearHeading {
	display: inline-flex;
	margin: 0;
	padding: 0;
	font: inherit;
	font-weight: inherit;
}

/* On a year page the label is also the way out to the list of every year. It
   gives no sign of that at rest -- the bar has two arrows in it already, and a
   third piece of obvious chrome would make the band busier than the
   photographs below it -- but it lifts to full contrast under the pointer.
   The site-wide a:hover rule outranks a single class, so every link state is
   stated here rather than inherited. */
a.yearLabel,
a.yearLabel:link,
a.yearLabel:visited,
a.yearLabel:active {
	color: #a6a6a6;
	text-decoration: none;
}

a.yearLabel:hover,
a.yearLabel:focus-visible {
	color: var(--dc-fg, #ffffff);
	text-decoration: none;
}

a.yearLabel:focus-visible {
	outline: 2px solid #0066ff;
	outline-offset: 4px;
	border-radius: 2px;
}

/* The list page's own label is the span of the archive rather than one year,
   so it needs room for "2009-2020" and has nowhere to link to. */
.yearLabel.is-static {
	min-width: 0;
}

/* On the index the label is not a link and not a control -- it is simply the
   name of the page, so it is the <h1>. Only the heading defaults a browser
   would add need clearing; every visible property still comes from .yearLabel. */
h1.yearLabel {
	margin: 0;
	padding: 0;
	font-size: 19px;
	font-weight: inherit;
	line-height: inherit;
}

.yearBar.is-stuck h1.yearLabel {
	font-size: 15px;
}

.yearBar.is-stuck .yearLabel {
	font-size: 15px;
	letter-spacing: 2.2px;
}

.yearStep {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	width: 30px;
	height: 30px;
	border-radius: 50%;
	color: #8a8a8a;
	line-height: 0;
	text-decoration: none;
	transition: color 180ms ease, background-color 180ms ease;
}

.yearBar.is-stuck .yearStep svg {
	width: 15px;
	height: 15px;
}

a.yearStep:hover,
a.yearStep:focus-visible {
	color: var(--dc-fg, #ffffff);
	background-color: rgba(255, 255, 255, 0.08);
}

a.yearStep:focus-visible {
	outline: 2px solid #0066ff;
	outline-offset: 2px;
}

/* The far end of the archive. The arrow stays in place so the control does not
   change shape, but it reads as unavailable. */
.yearStep.is-disabled {
	color: #4a4a4a;
	pointer-events: none;
}

/* --------------------------------------------------------------------------
   Year picker

   The list of years opens out of the year itself rather than beside it. The
   row for the year you are on is positioned over the label it came from, so
   opening the list does not move the thing you just clicked: the other years
   simply appear above and below it. Two years of context each way is enough to
   show which direction is which without turning the bar into a menu.

   Everything here is absolute or fixed-height on purpose. The row for the
   current year has to line up with the label to within a pixel, and the script
   measures that alignment after opening -- so anything that changes the menu's
   height while it is open, such as a scroll hint appearing, would pull the list
   off its anchor. The hints are therefore overlays on the list, not rows in it.
   -------------------------------------------------------------------------- */

.yearPick {
	position: relative;
	display: inline-flex;
}

.yearMenu {
	position: absolute;
	top: 0;
	left: 50%;
	z-index: 60;
	display: flex;
	flex-direction: column;
	min-width: 92px;
	padding: 5px;
	border-radius: 10px;
	/* Nearly opaque, and darker than the bar it grows out of. The blur behind it
	   keeps the photographs moving under the edges, but a list of small years
	   has to be readable over a headline as well as over a picture, and at the
	   bar's own 0.78 the masthead ghosts straight through the top rows. */
	background-color: rgba(26, 26, 26, 0.97);
	backdrop-filter: blur(18px) saturate(140%);
	-webkit-backdrop-filter: blur(18px) saturate(140%);
	border: 1px solid rgba(255, 255, 255, 0.1);
	box-shadow: 0 14px 34px rgba(0, 0, 0, 0.55);
	opacity: 0;
	transition: opacity 130ms ease;
}

/* display:flex above would otherwise defeat the attribute, and the attribute is
   what keeps the list out of sight when the script has not run. */
.yearMenu[hidden] {
	display: none;
}

.yearMenu.is-open {
	opacity: 1;
}

.yearMenuList {
	list-style: none;
	margin: 0;
	padding: 0;
	/* Five rows: the current year with two either side. */
	max-height: calc(var(--dc-yearrow, 34px) * 5);
	overflow-y: auto;
	/* The list is a small thing floating over a long page; without this, running
	   out of years hands the wheel straight to the page behind it. */
	overscroll-behavior: contain;
	/* A scrollbar would take width out of the rows and pull the year off centre
	   from the label above it. The fades at either end say the same thing. */
	scrollbar-width: none;
}

.yearMenuList::-webkit-scrollbar {
	width: 0;
	height: 0;
}

.yearMenuItem,
.yearMenuAll {
	display: flex;
	align-items: center;
	justify-content: center;
	height: var(--dc-yearrow, 34px);
	border-radius: 6px;
	white-space: nowrap;
	text-decoration: none;
	transition: color 140ms ease, background-color 140ms ease;
}

/* Set at the same size and tracking as the label, so the row that lands on the
   label is the label. The site-wide a:hover rule outranks a single class, so
   every state is stated rather than inherited. */
.yearMenuItem,
.yearMenuItem:link,
.yearMenuItem:visited,
.yearMenuItem:active {
	font-family: var(--dc-font-display);
	font-size: 19px;
	letter-spacing: 3px;
	/* Tracking adds a gap after the last digit, which reads as the year sitting
	   left of centre. Half of it back closes that. */
	text-indent: 3px;
	color: #8a8a8a;
	text-decoration: none;
}

.yearMenuItem:hover,
.yearMenuItem:focus-visible {
	color: var(--dc-fg, #ffffff);
	background-color: rgba(255, 255, 255, 0.08);
	text-decoration: none;
}

/* The year you are on. It is not a destination, but it is the anchor the whole
   list is positioned around, so it reads at full strength and the rest sit
   back from it. */
.yearMenuItem.is-current,
.yearMenuItem.is-current:link,
.yearMenuItem.is-current:visited {
	color: var(--dc-fg, #f2f2f2);
}

.yearMenuItem:focus-visible,
.yearMenuAll:focus-visible {
	outline: 2px solid #0066ff;
	outline-offset: -2px;
}

/* The way out to every year at once, kept below a hairline so it reads as a
   different kind of destination from the years above it. */
.yearMenuAll,
.yearMenuAll:link,
.yearMenuAll:visited,
.yearMenuAll:active {
	height: 30px;
	margin-top: 5px;
	padding-top: 5px;
	border-top: 1px solid rgba(255, 255, 255, 0.11);
	border-radius: 0 0 6px 6px;
	font-size: 12px;
	letter-spacing: 1.4px;
	color: #8a8a8a;
	text-decoration: none;
}

.yearMenuAll:hover,
.yearMenuAll:focus-visible {
	color: var(--dc-fg, #ffffff);
	background-color: rgba(255, 255, 255, 0.06);
	text-decoration: none;
}

/* There are more years this way. A strip of its own above and below the list
   rather than a badge floating over the end rows: overlaid, it sat on the very
   digits it was pointing at. It keeps its height whether or not it has anything
   to say, because the list is anchored to a measurement of where its rows are
   and a strip that appeared would push them off the label. */
.yearMenuStep {
	flex: 0 0 auto;
	height: 17px;
	display: flex;
	align-items: center;
	justify-content: center;
	color: #cfcfcf;
	cursor: pointer;
	opacity: 1;
	transition: opacity 160ms ease;
}

/* Nothing that way. It stops taking clicks as well as light, so a dead arrow
   never swallows one. */
.yearMenuStep.is-off {
	opacity: 0;
	pointer-events: none;
}

/* The label sheds its size when the bar pins, and the list has to follow it or
   the year would change size as the list opens. */
.yearBar.is-stuck .yearMenuItem {
	font-size: 15px;
	letter-spacing: 2.2px;
	text-indent: 2.2px;
}

/* Fixed 640px tracks, not fractions of the container.

   The photographs are 640x426 and there are no larger originals, so any track
   width other than 640 makes the browser resample every frame on the page. A
   fluid 1fr grid was doing exactly that: 636px at 1440, 625.5px at 1366,
   582.5px at 1280 -- scale factors just under 1, which is the worst case there
   is. There is no real size reduction to hide the interpolation, so each output
   pixel is a blend of two neighbours and the whole page reads slightly soft.
   The 1366 case was landing on a half pixel as well. Rendering at exactly 640
   maps one image pixel to one CSS pixel, which is why the home page rotator has
   always looked crisper than this grid did.

   auto-fit does the responsive work without a breakpoint: two tracks while the
   container can hold 1308px, one below that, centred either way. Only below
   672px -- phones, where the pixel ratio hides the resampling anyway -- does the
   frame have to go fluid, and that is handled at the bottom of this file. */
.showGrid {
	list-style: none;
	margin: 0;
	padding: 0;
	display: grid;
	grid-template-columns: repeat(auto-fit, 640px);
	justify-content: center;
	gap: 46px 28px;
}

/* Once the grid is a single column the horizontal gutter is gone, so the
   vertical rhythm tightens to match. */
@media (max-width: 1331px) {
	.showGrid {
		gap: 38px 0;
	}
}

/* Below the frame's own width there is no choice but to scale it. */
@media (max-width: 671px) {
	.showGrid {
		grid-template-columns: minmax(0, 1fr);
	}
}

/* On a phone the frame is around 370px wide rather than 640, but the caption
   was still being set at desktop sizes, so it ate a quarter of the photograph.
   The type scales with the frame; the panel's job of covering the watermark
   does not change, so min-width stays. */
@media (max-width: 560px) {
	:root {
		--cap-drop: 13px;
		--cap-min: 54px;
	}

	.stream {
		padding: 14px 0 10px;
	}

	.showCaption {
		padding: 5px 9px 6px 16px;
		font-size: 11px;
	}

	.showArtist {
		font-size: 12px;
	}

	.showDate {
		font-size: 9px;
	}
}

/* At the small end the panel is competing with a frame barely 300px wide, so
   every element steps down once more and the padding closes up. The point is
   to keep it hugging the wordmark rather than growing into the picture: below
   this width the three lines of text are what set the panel's height, not
   --cap-min, so type size is the only lever left.

   There is room for it. The wordmark is a fixed fraction of the frame -- the
   bottom 8.7% -- so on a 288px frame it is 17px tall, and the panel still puts
   about 35px on the image. --cap-inset needs no override at any width because
   it is a percentage. */
@media (max-width: 420px) {
	:root {
		--cap-drop: 11px;
		--cap-min: 44px;
	}

	.showCaption {
		padding: 4px 7px 5px 13px;
		font-size: 10px;
	}

	.showArtist {
		font-size: 11px;
		text-underline-offset: 2px;
	}

	.showDate {
		font-size: 8px;
	}
}

.show {
	min-width: 0;
	transition: opacity 280ms ease;
}

/* Hovering one photograph steps the others back, so the eye has somewhere to
   rest on a page that is otherwise eighty competing frames. The dim applies to
   the whole show -- caption and rotator included -- because dimming only the
   image would leave the captions floating at full strength.

   This does make every dimmed show a stacking context, which switches off the
   caption's backdrop-filter for as long as the dim is applied. That is fine
   now and was not before: the gradient does the masking, so losing the blur
   costs a little softness in the panel's open corner and nothing else. An
   overlay pseudo-element was tried here to avoid the stacking context and it
   defeated the filter just as thoroughly. */
.showGrid:hover .show:not(:hover):not(:focus-within) {
	opacity: 0.62;
}

/* The frame carries the shadow rather than the image, so the crossfade below
   does not fade the shadow in and out with it. The two-part shadow is doing
   what the tiled photo wall does on the home page: a tight contact shadow to
   seat the photograph, and a wide soft one to lift it off the background. */
.showFrame {
	position: relative;
	line-height: 0;
	box-shadow:
		0 1px 2px rgba(0, 0, 0, 0.55),
		0 10px 26px rgba(0, 0, 0, 0.45);
}

.showSlide {
	display: block;
	position: relative;
	text-decoration: none;
	opacity: 0;
	transition: opacity 560ms ease;
}

/* The first slide stays in flow so it sets the frame's height; the rest are
   stacked on top of it. Every slide in a show is 640x426, so nothing shifts
   when the rotator advances. */
.showSlide + .showSlide {
	position: absolute;
	inset: 0;
}

.showSlide.is-active {
	opacity: 1;
	z-index: 1;
}

.showSlide img {
	display: block;
	width: 100%;
	height: auto;
	border: 0;
}

/* --------------------------------------------------------------------------
   Caption

   Same anatomy as the home page rotator -- bottom right, artist in bold, date
   small underneath -- but the fill is sampled from the photograph behind it at
   build time by tools/sample-overlay-colors.ps1 rather than being a flat grey.

   The caption's real job is covering the burned-in davidconger.com watermark,
   so it has to be close to opaque; tinting it is what stops that opacity
   reading as a grey sticker slapped over the frame.
   -------------------------------------------------------------------------- */

.showCaption {
	position: absolute;
	right: var(--cap-inset);
	/* The panel hangs off the bottom of the photograph. It only has to cover
	   the wordmark, which is the bottom 9% of the frame; three lines of text
	   are taller than that, and the surplus was sitting on the picture for no
	   reason. Dropping it puts the surplus on the page instead. The join is
	   invisible because the ramp is fully opaque long before the frame's edge,
	   so the part over the photograph and the part over the page render the
	   same colour. */
	bottom: calc(-1 * var(--cap-drop));
	display: flex;
	flex-direction: column;
	justify-content: flex-end;
	box-sizing: border-box;
	min-height: var(--cap-min);
	text-decoration: none;
	/* The burned-in davidconger.com wordmark starts 73% of the way across the
	   frame, so the panel needs to reach at least that far left whatever the
	   text does -- 32% gives it that with a little margin for the measurement.
	   It used to be 36%, which pushed the panel noticeably past the wordmark
	   behind short names. */
	min-width: 32%;
	max-width: 92%;
	padding: 7px 18px 8px 18px;
	text-align: center;
	line-height: 1.35;
	/* The panel is a ramp, not a flat fill, and that is a correctness decision
	   as much as a visual one.

	   It has two jobs that pull against each other: let the photograph read
	   through, and completely hide the burned-in davidconger.com wordmark in
	   the bottom-right. A single even alpha cannot do both -- anything
	   transparent enough to see through is transparent enough to read the mark
	   through. Running the ramp corner to corner separates them in space: the
	   top-left, where nothing is hiding, opens right up, and the fill is solid
	   by the time it reaches the mark.

	   The stop is 12% rather than something more generous because the panel
	   shrinks to its 32% floor behind short artist names, and on that narrow a
	   panel the wordmark begins only about 15% along the diagonal. The end of
	   the ramp must stay at 0.99 or above: at 0.96 the mark ghosts back,
	   because a few percent of a white mark over a dark panel is still
	   legible.

	   The blur is a bonus on top, not the mechanism. It was tried as the
	   mechanism -- heavy blur over an evenly translucent panel, on the theory
	   that letterforms are high frequency and would smear away -- and it does
	   work, right up until anything makes an ancestor a stacking context. A
	   transform, an opacity, a filter on any parent turns backdrop-filter into
	   a no-op silently, and the watermark comes back on every frame at once.
	   The hover dim did exactly that. Masking cannot rest on something that
	   fragile, so the gradient carries it and the blur only softens what shows
	   through the open end. */
	background-image: linear-gradient(135deg, var(--cap-top, rgba(38, 38, 38, 0.5)) 0%, var(--cap-bot, rgba(30, 30, 30, 0.995)) 12%);
	backdrop-filter: blur(20px) saturate(1.25);
	-webkit-backdrop-filter: blur(20px) saturate(1.25);
	color: var(--cap-fg, rgba(255, 255, 255, 0.88));
	font-size: 12px;
	/* Same shadow as the frame, for the same reason: once the panel is inset
	   from the corner it needs seating, and the shadow is also what stops its
	   bottom edge ending abruptly against the page. The inset hairline is a
	   third layer of the same property -- photographs are noisy, and a tinted
	   panel can land within a few percent of the pixels beside it, so a line
	   of light along the top edge keeps it legible without drawing a border. */
	box-shadow:
		0 1px 2px rgba(0, 0, 0, 0.55),
		0 10px 26px rgba(0, 0, 0, 0.45),
		inset 0 1px 0 rgba(255, 255, 255, 0.07);
}

.showArtist {
	display: block;
	font-weight: 600;
	font-size: 14px;
	text-decoration-line: underline;
	text-decoration-color: transparent;
	text-decoration-thickness: 1px;
	text-underline-offset: 3px;
	transition: text-decoration-color 180ms ease;
}

/* Anywhere on the caption is the link, but the caption also has to keep
   reading as a caption -- so the only sign it gives is an underline arriving
   under the artist's name. The site-wide a:hover rule would otherwise turn the
   whole panel blue and underline all three lines, and it outranks a single
   class, so the caption states its own colour in every link state. */
.showCaption,
.showCaption:link,
.showCaption:visited,
.showCaption:hover,
.showCaption:focus,
.showCaption:active {
	color: var(--cap-fg, rgba(255, 255, 255, 0.88));
	text-decoration: none;
}

.showCaption:hover .showArtist,
.showCaption:focus-visible .showArtist {
	text-decoration-color: currentColor;
}

.showCaption:focus-visible {
	outline: 2px solid #0066ff;
	outline-offset: 2px;
}

/* The frame is the rotator's own control: clicking a photograph brings up the
   next one. Shows with a single frame have nothing to advance to, so they get
   no pointer. */
.has-rotator .showFrame {
	cursor: pointer;
}

.showVenue {
	display: block;
	opacity: 0.82;
}

.showDate {
	display: block;
	font-size: 10px;
	letter-spacing: 0.5px;
	opacity: 0.66;
}

/* --------------------------------------------------------------------------
   Rotator

   Deliberately below the photograph and deliberately small. Controls on top of
   the image would compete with the caption and cover more of the frame, and
   the whole point of this layout is that the photograph is the content.

   Left-aligned, because the caption now hangs into this row on the right. The
   two finish on the same baseline, so the strip below each frame reads as one
   deliberate band rather than two things that happen to be near each other.
   -------------------------------------------------------------------------- */

.showDots {
	display: flex;
	justify-content: flex-start;
	align-items: flex-end;
	gap: 8px;
	height: var(--cap-drop);
	/* Inset by the same amount the caption is, so the two ends of the strip
	   below the frame sit an equal distance in from their edges. */
	padding: 0 0 0 calc(var(--cap-inset) + 2px);
	line-height: 0;
}

.showDots button {
	width: 7px;
	height: 7px;
	padding: 0;
	border: 0;
	border-radius: 50%;
	background: #4c4c4c;
	cursor: pointer;
	transition: background 180ms ease, transform 180ms ease;
}

.showDots button:hover {
	background: #0066ff;
}

.showDots button[aria-selected="true"] {
	background: #c9c9c9;
	transform: scale(1.18);
}

.showDots button:focus-visible {
	outline: 2px solid #0066ff;
	outline-offset: 3px;
}

@media (prefers-reduced-motion: reduce) {
	.showSlide,
	.showDots button {
		transition: none;
	}
}

/* The year list at /galleries/. Each card is a rotator like any other, but its
   caption is navigation rather than a credit: the year is the whole point of
   the card, and "View" above it says the panel is the way in. The underline is
   there for the same reason -- nothing else on these pages is a text link, so
   without it the panel reads as a label. */
.yearCaption {
	justify-content: center;
}

.yearCaptionLead {
	display: block;
	font-size: 12px;
	letter-spacing: 2.6px;
	text-transform: uppercase;
	opacity: 0.78;
}

.yearCaptionYear {
	display: block;
	margin-top: 1px;
	font-family: var(--dc-font-display);
	font-size: 30px;
	font-weight: 600;
	letter-spacing: 3px;
	line-height: 1.1;
	text-decoration-line: underline;
	text-decoration-color: rgba(255, 255, 255, 0.38);
	text-decoration-thickness: 1px;
	text-underline-offset: 4px;
	transition: text-decoration-color 180ms ease;
}

.show:hover .yearCaptionYear,
.yearCaption:focus-visible .yearCaptionYear {
	text-decoration-color: currentColor;
}

/* --------------------------------------------------------------------------
   Home page
   The home page is one show in the same grid the year pages use, so almost
   everything above applies unchanged. What differs is the band under the
   masthead: where a year page carries its year, the home page carries the three
   sections of the site. Same band, same weight, so the two pages read as the
   same design rather than as two that happen to share a header.
   -------------------------------------------------------------------------- */

.yearBar .siteNav {
	display: flex;
	align-items: center;
	justify-content: center;
	flex-wrap: wrap;
	gap: 6px 30px;
	padding: 0;
}

/* Matched to .yearLabel, and stating every link state because the site-wide
   a:hover rule -- specificity (0,1,1) -- outranks any single class and would
   otherwise turn these blue.

   These three keep their underline. Everywhere else on the site a link is
   either a photograph or a caption and its target is obvious; here it is three
   words in a band, and without the rule under them they read as a heading
   rather than as the way into the site. The rule is held back from full
   strength so it sits under the words instead of boxing them in. */
.yearBar .siteNav a,
.yearBar .siteNav a:link,
.yearBar .siteNav a:visited,
.yearBar .siteNav a:active {
	font-family: var(--dc-font-display);
	font-size: 15px;
	letter-spacing: 2.2px;
	color: #dcdcdc;
	text-decoration: underline;
	text-decoration-color: rgba(255, 255, 255, 0.34);
	text-decoration-thickness: 1px;
	text-underline-offset: 5px;
	white-space: nowrap;
	transition: color 180ms ease, text-decoration-color 180ms ease;
}

.yearBar .siteNav a:hover,
.yearBar .siteNav a:focus-visible {
	color: var(--dc-fg, #ffffff);
	text-decoration: underline;
	text-decoration-color: rgba(255, 255, 255, 0.75);
}

.yearBar .siteNav a:focus-visible {
	outline: 2px solid #0066ff;
	outline-offset: 4px;
	border-radius: 2px;
}

/* The rotator is built from JSON after the page loads, so the show starts
   hidden rather than as an empty frame that collapses when the first slide
   arrives. .show sets its own display, which beats the [hidden] attribute's
   UA rule, so it has to be said again here. */
.show[hidden] {
	display: none;
}

/* The wall of past work behind the featured photograph. It is the same band
   the home page has carried since 2015 -- a tiled sheet of frames, dimmed, with
   the fade to background baked into the top and bottom of the tile itself, so
   nothing here has to mask it.

   Reaching both edges of the window is done by cancelling the body padding on
   <main> rather than by a 100vw child. 100vw counts the scrollbar, so it always
   overhangs by its width and puts a horizontal scrollbar on the page; negative
   margins are exact. */
.homeStream {
	position: relative;
	/* The 1308px cap the rest of the stream keeps is what was holding the band
	   short of the window edge, and it buys nothing here: the home page is one
	   640px card, which the grid centres on its own. */
	max-width: none;
	margin-left: -12px;
	margin-right: -12px;
	padding-left: 12px;
	padding-right: 12px;
}

.homeWall {
	position: absolute;
	/* .stream's own padding-top, so the band starts level with the photograph. */
	top: 17px;
	left: 0;
	right: 0;
	/* One tile tall, until the photograph is smaller than that. Below roughly
	   660px the frame shrinks to fit the window, and a fixed band would hang
	   past the bottom of the picture and the dots below it; the second term is
	   the frame's own height, 426/640 of its width. background-size scales the
	   tile to match, which keeps the fade to background that is painted into
	   its top and bottom edges. */
	height: min(425px, calc((100vw - 24px) * 0.6656));
	background: url("../images/2015-background.jpg") repeat-x center top;
	background-size: auto 100%;
	pointer-events: none;
}

.homeGrid {
	position: relative;
}

/* There is only one show on the home page, so the rule that steps the others
   back has nothing to act on -- but it still fires for the instant the pointer
   is inside the grid and outside the photograph, which reads as an unexplained
   flicker on the way out. */
.homeGrid:hover .show:not(:hover):not(:focus-within) {
	opacity: 1;
}

.homeGrid .show {
	transition: none;
}

@media (max-width: 560px) {
	.yearBar .siteNav {
		gap: 4px 18px;
	}

	.yearBar .siteNav a,
	.yearBar .siteNav a:link,
	.yearBar .siteNav a:visited,
	.yearBar .siteNav a:active {
		font-size: 13px;
		letter-spacing: 1.4px;
	}
}

/* --------------------------------------------------------------------------
   Individual gallery pages

   Everything below is scoped to body.galleryPage on purpose. #gallery,
   #details and #images are also the containers used by roughly five thousand
   pages under /you/, which is live and out of scope, so none of these rules
   may be allowed to reach them. The class is the fence.
   -------------------------------------------------------------------------- */

/* Foldered gallery pages are a single 640px column: one photograph per row, at
   the size it was made for, with nothing beside it competing for attention.

   Portraits are the exception, and the generator already expressed it -- 1,060
   of the 1,064 multi-image list items on these pages are a pair of 426x640
   portraits sharing one <li>, because two portraits side by side occupy the
   same landscape-shaped row a single 640x426 frame does. Left in a two-column
   grid that intent was invisible; in one column it is the layout. No markup
   change is needed for it, only the column count. */
.galleryPage #gallery {
	max-width: 640px;
	margin: 0 auto;
	padding: 0;
}

/* The title block reads top-down -- who, then what tour, then where, then
   when -- so each line gets its own weight rather than all four arriving at
   once. The generators separated the lines with <br>, which leaves no room to
   space them; the breaks are dropped and the spans made blocks instead. */
.galleryPage #gallery #details {
	padding: 14px 12px 26px;
	font-family: var(--dc-font-display);
}

.galleryPage:not(.flatGallery) #gallery #details br {
	display: none;
}

.galleryPage:not(.flatGallery) #gallery #details span {
	display: block;
	line-height: 1.5;
}

.galleryPage #gallery #details #title {
	margin-bottom: 0;
	font-size: 26px;
	font-weight: 600;
	letter-spacing: 3px;
	line-height: 1.2;
	color: var(--dc-fg, #ffffff);
}

.galleryPage #gallery #details #tour {
	font-size: 14px;
	letter-spacing: 2px;
	color: #a6a6a6;
}

.galleryPage #gallery #details #venue {
	font-size: 14px;
	letter-spacing: 1.6px;
	color: #8a8a8a;
}

.galleryPage #gallery #details #date {
	margin-top: 3px;
	font-size: 12px;
	letter-spacing: 1.8px;
	text-transform: uppercase;
	color: #6f6f6f;
}

.galleryPage #gallery #images {
	padding: 0;
	display: grid;
	/* One track, never wider than the frame and free to shrink below it, so no
	   breakpoint is needed to get the photographs down onto a phone. */
	grid-template-columns: minmax(0, 640px);
	justify-content: center;
	align-items: start;
	gap: 38px 0;
}

.galleryPage #gallery #images li {
	padding: 0;
	margin: 0;
	min-width: 0;
}

/* The 2013-2015 pages wrap every photograph in a pair of .shareOuter elements
   left over from the Facebook share overlay. The overlay is gone; the wrappers
   stay because they are inside the gallery markup, so they are flattened to
   nothing rather than removed from a thousand files.

   The generator also puts *two* portrait frames inside a single <li> -- 1,061
   of them across 730 pages -- because a pair of 426x640 portraits was always
   meant to occupy one landscape-shaped row rather than tower over it. Both the
   list item and the surviving wrappers are laid out as a centred flex row so
   that pair sits side by side and shrinks to fit the column, exactly as the
   flat legacy pages do. A lone photograph is unaffected: a one-item centred
   flex row renders identically to the block it replaces. */
.galleryPage #gallery #images li,
.galleryPage #gallery #images li .shareOuter {
	display: flex;
	justify-content: center;
	align-items: flex-start;
	gap: 12px;
	line-height: 0;
}

/* No border -- the frame is seated with a shadow instead, the same two-part
   one the year pages use: a tight contact shadow, and a wide soft one to lift
   it off the background. */
.galleryPage #gallery #images li img {
	display: block;
	margin: 0;
	min-width: 0;
	max-width: 100%;
	height: auto;
	border: 0;
	box-shadow:
		0 1px 2px rgba(0, 0, 0, 0.55),
		0 10px 26px rgba(0, 0, 0, 0.45);
}

/* The way back to the year. It sits next to Home as the second half of a
   breadcrumb, and stays close to the background until the pointer reaches it
   -- the page is a set of photographs, and navigation should not compete with
   them. The site-wide a:hover rule outranks a single class, so every state is
   spelled out. */
.crumbYear,
.crumbYear:link,
.crumbYear:visited,
.crumbYear:active {
	font-family: var(--dc-font-display);
	font-size: 15px;
	letter-spacing: 2.4px;
	line-height: 1;
	color: #6f6f6f;
	text-decoration: none;
	transition: color 180ms ease;
}

.crumbYear:hover,
.crumbYear:focus-visible {
	color: var(--dc-fg, #ffffff);
	text-decoration: none;
}

.crumbYear:focus-visible {
	outline: 2px solid #0066ff;
	outline-offset: 4px;
	border-radius: 2px;
}

/* Home and the crumb were separated by nothing but whitespace, which reads as
   two unrelated controls rather than a path. A chevron says "one step down
   from here" -- the same thing the year arrows either side of this bar say,
   drawn the same way -- where a pipe would only say the two are siblings.

   It is generated content rather than markup so that it costs nothing on
   11,000 pages, and it carries an empty alt string so a screen reader announces
   the link as "2020" and not "angle bracket 2020". The plain `content` above
   is the fallback for browsers that do not know the alt syntax; they get the
   chevron, just without the silencing. Its colour is set here and never
   changed, so it stays put while the crumb itself lights up on hover. */
.streamHome .crumbYear::before {
	content: "\203A";
	content: "\203A" / "";
	display: inline-block;
	margin-right: 11px;
	color: #4a4a4a;
	font-family: var(--dc-font-display);
	font-size: 17px;
	letter-spacing: 0;
	vertical-align: -1px;
}

@media (max-width: 560px) {
	.galleryPage #gallery #details {
		padding: 5px 8px 18px;
	}

	.galleryPage #gallery #details #title {
		font-size: 21px;
		letter-spacing: 2.2px;
	}

	.galleryPage #gallery #images {
		gap: 20px 0;
	}
}
/* --------------------------------------------------------------------------
   The flat legacy galleries -- galleries/<slug>.htm, 2009-2012

   These predate the foldered generator and keep their photographs in a mix of
   <p> and two-column <table> blocks rather than a list. The blocks are left
   exactly as they are, because every link out to Flickr lives inside them; the
   styling here only removes the old white border, seats each photograph with
   the same shadow the rest of the site uses, and stops the fixed-width tables
   from overflowing a phone.

   Unlike the foldered galleries the title block here is loose text separated by
   <br>, not one span per line, so those breaks have to stay.
   -------------------------------------------------------------------------- */

.flatGallery #gallery {
	max-width: 720px;
}

.flatGallery #gallery #details {
	font-size: 14px;
	letter-spacing: 1.4px;
	line-height: 1.5;
	color: #8a8a8a;
}

.flatGallery #gallery #details #title {
	display: block;
	margin-bottom: 0;
	font-size: 26px;
	font-weight: 600;
	letter-spacing: 3px;
	line-height: 1.2;
	color: var(--dc-fg, #ffffff);
}

/* The page's own inline <style> sets these; they are the small print under the
   date, and the second is the artist span on the 2011-era pages. */
.flatGallery #gallery #details .style1 {
	font-size: 12px;
	letter-spacing: 1.4px;
	color: #6f6f6f;
}

.flatGallery #gallery #details .style2 {
	font-weight: 600;
	letter-spacing: 3px;
}

.flatGallery #gallery #details a,
.flatGallery #gallery #details a:link,
.flatGallery #gallery #details a:visited,
.flatGallery #gallery #details a:active {
	color: #a6a6a6;
	text-decoration: underline;
	text-decoration-color: rgba(255, 255, 255, 0.3);
	text-underline-offset: 3px;
}

.flatGallery #gallery #details a:hover,
.flatGallery #gallery #details a:focus-visible {
	color: var(--dc-fg, #ffffff);
	text-decoration: underline;
	text-decoration-color: currentColor;
}

.flatImages p {
	margin: 0 0 30px;
}

.flatImages img,
.flatGallery .galleryphoto {
	display: inline-block;
	max-width: 100%;
	height: auto;
	border: 0;
	box-shadow:
		0 1px 2px rgba(0, 0, 0, 0.55),
		0 10px 26px rgba(0, 0, 0, 0.45);
}

.flatGallery .galleryphoto:hover {
	border: 0;
}

/* The two-up blocks were laid out with a 700px table, which is wider than a
   phone. The width is inline, so overriding it needs the flag. */
.flatImages table {
	width: auto !important;
	max-width: 100%;
	margin: 0 auto 30px;
	border-collapse: collapse;
}

.flatImages td {
	padding: 0 6px;
	vertical-align: top;
}

@media (max-width: 720px) {
	.flatImages table,
	.flatImages tbody,
	.flatImages tr,
	.flatImages td {
		display: block;
		width: auto !important;
	}

	.flatImages td {
		padding: 0 0 30px;
	}

	.flatGallery #gallery #details #title {
		font-size: 21px;
		letter-spacing: 2.2px;
	}
}
/* --------------------------------------------------------------------------
   Section pages

   Everything outside the galleries and /you/: the catalogs, the by-date and
   by-artist listings, the festival and radio pages, About and the 404. They
   share the chrome now, so all that is left here is to give their content the
   same type and spacing the rest of the site uses.
   -------------------------------------------------------------------------- */

/* The class is on the body and on the main element both, so an unqualified
   padding here would be spent twice: once between the content and the footer
   and again below the footer. The footer sets its own space above. */
main.pageStream {
	padding-bottom: 8px;
}

body.pageStream {
	padding-bottom: 26px;
}

/* .stream sets a 1308px measure, which is right for a grid of photographs and
   far too wide for a column of text. Reading pages take it back. */
main.prose.pageStream {
	max-width: 760px;
	padding-top: 8px;
}

.prose.pageStream h1 {
	margin: 0 0 18px;
	font-size: 26px;
	font-weight: 600;
	letter-spacing: 0.4px;
	color: #f2f2f2;
}

.prose.pageStream h2 {
	margin: 34px 0 6px;
	font-size: 12px;
	font-weight: 600;
	letter-spacing: 2.4px;
	text-transform: uppercase;
	color: #9a9a9a;
}

.prose.pageStream p {
	margin: 0 0 14px;
	font-size: 15px;
	line-height: 1.65;
	color: #cfcfcf;
}

.prose.pageStream .orgName {
	margin: 12px 0 2px;
	font-size: 16px;
	font-weight: 600;
	color: #ececec;
}

/* Station and format lists. x-small was unreadable against this background. */
.prose.pageStream .fine {
	margin: 0 0 4px;
	font-size: 13px;
	line-height: 1.55;
	color: #8f8f8f;
}

.prose.pageStream .plainList {
	margin: 4px 0 16px;
	font-size: 15px;
	line-height: 1.7;
	color: #cfcfcf;
}

.prose.pageStream ul:not(.plainList) {
	margin: 0 0 16px;
	padding-left: 20px;
	font-size: 15px;
	line-height: 1.8;
	color: #cfcfcf;
}

/* The client logos are white artwork on transparent, so they sit a little hot
   against a near-black page. Holding them just under full strength lets the
   headings stay the brightest thing in the column. */
.prose.pageStream .clientLogos {
	gap: 18px;
	margin: 14px 0 6px;
	opacity: 0.72;
	transition: opacity 200ms ease;
}

.prose.pageStream .clientLogos:hover {
	opacity: 1;
}

.prose.pageStream hr {
	margin: 30px 0 18px;
	border: 0;
	border-top: 1px solid rgba(255, 255, 255, 0.1);
}

.prose.pageStream .memoriam {
	color: #8f8f8f;
	font-style: italic;
}

/* site.css:96 `a:hover` is (0,1,1) and beats a single class, so every state has
   to be restated or the hover reverts to the old blue with an underline. */
.prose.pageStream a:link,
.prose.pageStream a:visited {
	color: #dcdcdc;
	text-decoration: underline;
	text-decoration-color: rgba(255, 255, 255, 0.34);
	text-underline-offset: 4px;
}

.prose.pageStream a:hover,
.prose.pageStream a:focus,
.prose.pageStream a:active {
	color: #ffffff;
	text-decoration: underline;
	text-decoration-color: rgba(255, 255, 255, 0.75);
}
/* --------------------------------------------------------------------------
   Meet and greet pages (/you/)

   Same chrome as everywhere else, but the photographs want the opposite
   treatment to the concert galleries. These are not watermarked and they are
   not portfolio pieces -- they belong to the person in them -- so there is no
   caption overlay, nothing sits on top of the image, and the frame is a shadow
   rather than the old white hairline.

   Three list ids are in play, laid down by three generations of the generator:
   #youimages is the thumbnail grid, #images and #youimage are the full photo.
   -------------------------------------------------------------------------- */

.youPage #gallery {
	max-width: 1308px;
	padding: 0 0 16px;
}

.youPage #gallery #details {
	padding: 4px 20px 4px;
	font-family: var(--dc-font);
	color: #cfcfcf;
}

.youPage #gallery #details #title {
	display: block;
	margin-bottom: 0;
	font-size: 22px;
	line-height: 1.3;
	font-weight: 600;
	letter-spacing: 2.6px;
	color: #f2f2f2;
}

.youPage #gallery #details #venue {
	display: block;
	font-size: 15px;
	letter-spacing: 0.4px;
	color: #b4b4b4;
}

.youPage #gallery #details #date {
	display: block;
	margin-top: 2px;
	font-size: 12px;
	letter-spacing: 2.2px;
	text-transform: uppercase;
	color: #8a8a8a;
}

.youPage #gallery #details br {
	display: none;
}

/* The paragraph explaining how to save the photo, and the page navigation.
   Both used to be spaced by empty lines written into the markup; the space is
   set here now, so it can be tuned in one place. */
.youPage #gallery > div {
	font-size: 14px;
	line-height: 1.6;
	color: #a8a8a8;
}

.youPage #gallery .youIntro {
	margin-top: 14px;
}

.youPage #gallery > div.younavigation {
	margin-top: 22px;
}

/* The nav directly under the caption sits closer than the one after the photo,
   so the link reads as part of the title block rather than floating. */
.youPage #gallery #details + div.younavigation {
	margin-top: 6px;
}

.youPage .younavigation {
	font-size: 13px;
	letter-spacing: 0.6px;
}

/* Legacy spacer breaks inside the nav; spacing is handled with margins instead. */
.youPage .younavigation br {
	display: none;
}

.youPage .younavigation a:link,
.youPage .younavigation a:visited,
.youPage #gallery > div a:link,
.youPage #gallery > div a:visited {
	color: #dcdcdc;
	text-decoration: underline;
	text-decoration-color: rgba(255, 255, 255, 0.32);
	text-underline-offset: 4px;
}

.youPage .younavigation a:hover,
.youPage .younavigation a:focus,
.youPage .younavigation a:active,
.youPage #gallery > div a:hover,
.youPage #gallery > div a:focus,
.youPage #gallery > div a:active {
	color: #ffffff;
	text-decoration: underline;
	text-decoration-color: rgba(255, 255, 255, 0.75);
}

.youPage .navDisabled {
	color: #6a6a6a;
}

/* The thumbnail grid. Centred rather than left-aligned so a short last row
   sits under the middle of the one above it. */
.youPage #gallery #youimages {
	display: flex;
	flex-wrap: wrap;
	justify-content: center;
	gap: 18px;
	padding: 16px 0 0;
}

.youPage #gallery #youimages li {
	width: auto;
	margin: 0;
	padding: 0;
}

.youPage #gallery #youimages li a {
	display: block;
	line-height: 0;
}

/* site.css puts a 1px white border on all three of these. A border on a
   photograph reads as a mount; a shadow reads as the photograph sitting on the
   page, which is what the concert galleries do now too. Two shadows: a tight
   dark one for the edge and a wide soft one for the lift. */
.youPage #gallery #images li img,
.youPage #gallery #youimage li img,
.youPage #gallery #youimages li img {
	border: 0;
	margin: 0;
	box-shadow:
		0 1px 2px rgba(0, 0, 0, 0.5),
		0 14px 34px rgba(0, 0, 0, 0.45);
	transition: box-shadow 200ms ease;
}

.youPage #gallery #youimages li a:hover img,
.youPage #gallery #youimages li a:focus img {
	box-shadow:
		0 1px 2px rgba(0, 0, 0, 0.55),
		0 18px 44px rgba(0, 0, 0, 0.6);
}

.youPage #gallery #youimages li a:focus-visible img {
	outline: 2px solid #0066ff;
	outline-offset: 3px;
}

/* The full photograph, centred with room to breathe. */
.youPage #gallery #images,
.youPage #gallery #youimage {
	display: flex;
	justify-content: center;
	padding: 16px 0 0;
}

.youPage #gallery #images li,
.youPage #gallery #youimage li {
	margin: 0;
	padding: 0;
	max-width: 100%;
}

.youPage #gallery #images li img,
.youPage #gallery #youimage li img {
	max-width: 100%;
	height: auto;
}

@media (max-width: 720px) {
	.youPage #gallery #details #title {
		font-size: 19px;
		letter-spacing: 2px;
	}

	.youPage #gallery #youimages {
		gap: 12px;
	}
}
/* --------------------------------------------------------------------------
   Catalog grids

   The /you/ index, /you/previous.htm and the year catalogs under /catalog/ all
   use the same #catalog > ul.catalogList markup, so they get the same
   treatment: the thumbnails lose the white hairline for the shadow the rest of
   the site now uses, and the caption under each one is set as a caption rather
   than as body text.

   The /you/ archive grid is the exception -- it sits in .youArchive rather than
   #catalog, so the base sheet's `#catalog .catalogList` rules do not reach it.
   Rather than move those rules (nine catalog/list.htm pages still rely on them
   and carry no .pageStream class), each rule below that has to beat one of them
   is repeated with #catalog in the selector. Without that the two grids on
   /you/ would not match each other.
   -------------------------------------------------------------------------- */

.pageStream #catalog,
.pageStream .youArchive .catalogList {
	font-size: 13px;
}

.pageStream .catalogList,
.pageStream #catalog .catalogList {
	display: flex;
	flex-wrap: wrap;
	justify-content: center;
	gap: 39px 20px;
	margin: 0;
	padding: 8px 0 0;
	list-style: none;
}

.pageStream .catalogList li,
.pageStream #catalog .catalogList li {
	display: block;
	width: 240px;
	margin: 0;
	padding: 0;
	list-style: none;
}

.pageStream .catalogList li img,
.pageStream #catalog .catalogList li img {
	display: block;
	/* A handful of the older thumbnails were never cropped to the catalog's
	   240x160, so the box is enforced here rather than trusted from the file. */
	width: 240px;
	height: 160px;
	object-fit: cover;
	margin: 0 auto 10px;
	border: 0;
	box-shadow:
		0 1px 2px rgba(0, 0, 0, 0.5),
		0 12px 28px rgba(0, 0, 0, 0.42);
	transition: box-shadow 200ms ease;
}

.pageStream .catalogList li a:hover img,
.pageStream .catalogList li a:focus img {
	box-shadow:
		0 1px 2px rgba(0, 0, 0, 0.55),
		0 16px 38px rgba(0, 0, 0, 0.58);
}

.pageStream .catalogList li a:focus-visible img {
	outline: 2px solid #0066ff;
	outline-offset: 3px;
}

/* The <br> after each image is what the old generator used for the gap the
   margin now provides. The breaks between the event, the venue and the date do
   the same thing to no purpose at all: those three are blocks, so each break
   adds an empty line on top of the line the block already occupies, and the
   caption reads as three separate things rather than one. Hidden by tag name
   rather than wholesale, because the year catalogs under /catalog/ write their
   caption as a single run of text where the break is load-bearing. */
.pageStream .catalogList li img + br,
.pageStream .catalogList li event + br,
.pageStream .catalogList li venue + br {
	display: none;
}

.pageStream .catalogList li a:link,
.pageStream .catalogList li a:visited {
	display: block;
	color: #a8a8a8;
	line-height: 1.5;
	text-decoration: none;
}

.pageStream .catalogList li a:hover,
.pageStream .catalogList li a:focus,
.pageStream .catalogList li a:active {
	color: #e8e8e8;
	text-decoration: none;
}

.pageStream .catalogList li event {
	display: block;
	font-size: 14px;
	font-weight: 600;
	color: #ececec;
}

.pageStream .catalogList li venue,
.pageStream .catalogList li date {
	display: block;
}

.pageStream .catalogList li date {
	font-size: 11px;
	letter-spacing: 1.4px;
	text-transform: uppercase;
	color: #808080;
}

/* The heading block above the grid on the /you/ index and the year catalogs. */
.pageStream .pageHeader {
	display: block;
	margin-bottom: 6px;
	font-size: 12px;
	font-weight: 600;
	letter-spacing: 2.6px;
	text-transform: uppercase;
	color: #9a9a9a;
}

.pageStream .yearHeader {
	display: block;
	font-size: 21px;
	font-weight: 600;
	letter-spacing: 1px;
	color: #f2f2f2;
}

.pageStream #catalogNav,
.pageStream #dcCatalogNav,
.pageStream #dcListingNav {
	font-size: 13px;
	color: #8f8f8f;
}

/* Every earlier season, folded in from the old previous.htm so the whole run of
   events lives on one page. A hairline sets it apart from the thumbnail grid
   above without making it look like a different page.

   These years used to be a list of text links, because the retired generator
   never wrote a thumbnail for them. They do now, so the archive is the same grid
   as the seasons above it and needs none of the type or link styling a run of
   text needed -- only the rule, the spacing and the year headings. */
.pageStream .youArchive {
	margin-top: 34px;
	padding-top: 28px;
	border-top: 1px solid rgba(255, 255, 255, 0.1);
	color: #c8c8c8;
	text-align: center;
}

/* Long event names wrap on a phone; keep them off the edge of the screen. */
@media (max-width: 620px) {
	.pageStream .youArchive {
		padding-left: 14px;
		padding-right: 14px;
	}
}

.pageStream .youArchive .pageHeader {
	margin-bottom: 4px;
}

/* Each year heading sits above its own grid, so it needs clear air above it and
   only a little below, where the grid's own padding takes over. */
.pageStream .youArchive .yearHeader {
	margin: 38px 0 2px;
	font-size: 18px;
}

.pageStream .youArchive .pageHeader + .yearHeader {
	margin-top: 18px;
}

.pageStream #catalogNav a:link,
.pageStream #catalogNav a:visited,
.pageStream #dcCatalogNav a:link,
.pageStream #dcCatalogNav a:visited,
.pageStream #dcListingNav a:link,
.pageStream #dcListingNav a:visited {
	color: #dcdcdc;
	text-decoration: underline;
	text-decoration-color: rgba(255, 255, 255, 0.34);
	text-underline-offset: 4px;
}

.pageStream #catalogNav a:hover,
.pageStream #catalogNav a:focus,
.pageStream #dcCatalogNav a:hover,
.pageStream #dcCatalogNav a:focus,
.pageStream #dcListingNav a:hover,
.pageStream #dcListingNav a:focus {
	color: #ffffff;
	text-decoration: underline;
	text-decoration-color: rgba(255, 255, 255, 0.75);
}

.pageStream #catalog .catalogGroupHeader {
	font-size: 12px;
	font-weight: 600;
	letter-spacing: 2.6px;
	text-transform: uppercase;
	color: #9a9a9a;
}
/* The heading is a stack of blocks -- section, span of years, and the way back
   to the older ones -- so the breaks between them only add empty lines. Scoped
   to the breaks that follow those blocks: you/previous.htm puts its whole event
   list inside this same container and its breaks are load-bearing. */
/* The grid starts 30px below the last line of this block: 22 here and 8 on the
   list. Above it the site header and the stream have already spent 34px of
   their own padding before this block begins, so the surplus comes back off
   the top to frame the heading evenly. */
.pageStream .catalogIntro {
	margin-top: -4px;
	padding: 0 0 22px;
	text-align: center;
}

.pageStream .catalogIntro .pageHeader + br,
.pageStream .catalogIntro .pageHeader + br + br,
.pageStream .catalogIntro .yearHeader + br,
.pageStream .catalogIntro #catalogNav + br,
.pageStream .catalogIntro #catalogNav + br + br {
	display: none;
}

.pageStream .catalogIntro #catalogNav {
	display: block;
	margin-top: 2px;
}
