/* Reset and Base Styles */
* {
    margin: 0;
    padding: 0;
    box-sizing: border-box;
}

:root {
    /* Shared left/right inset: lines up with the title printed on the cover */
    --inset: 12px;
    /* Width of the right-hand column: the arrows and "2026" are both centred
       in it, so they share one centre line */
    --end: 52px;
    /* The arrow drawing, kept once so the two mask lines below cannot drift apart */
    --arrow: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none' stroke='%23000' stroke-width='2'%3E%3Cpath d='M1 8h12M9 3.5 13.5 8 9 12.5'/%3E%3C/svg%3E");
}

html {
    /* This design is light only: no automatic darkening by the browser */
    color-scheme: light;
    color-scheme: only light;
    /* Stop phones enlarging text when rotated. This spelling and value are the
       ones every browser reads, Firefox included (it rejects 100% and does not
       know the unprefixed name, and logged a console warning for each) */
    -webkit-text-size-adjust: none;
}

/* Page is a column: the frame area grows, the footer sits at the bottom */
body {
    font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
    background-color: #ffffff;
    color: #111111;
    display: flex;
    flex-direction: column;
    min-height: 100vh;
    min-height: 100dvh;
}

/* Selected text inverts, like a hovered row. The 0.99 alpha stops Chrome
   lightening an opaque selection colour */
::selection {
    background-color: rgba(17, 17, 17, 0.99);
    color: #ffffff;
}

/* Select-all must not black out the photo */
.cover img::selection {
    background-color: transparent;
}

/* Tap feedback in the page's own ink (Android's default is blue). Kept visible
   on purpose: on iPhones it can be the only sign of a press */
@supports (-webkit-tap-highlight-color: transparent) {
    a {
        -webkit-tap-highlight-color: rgba(17, 17, 17, 0.2);
    }
}

/* Container: fills the space above the footer and centres the frame in it */
.container {
    flex: 1;
    display: flex;
    justify-content: center;
    align-items: center;
    padding: 20px;
}

/* Phones: the frame starts at the top, so it does not jump when the browser
   toolbar hides while scrolling; only the footer follows the screen edge */
@media (max-width: 480px) {
    .container {
        align-items: flex-start;
        /* When the screen is taller than the page, share the spare space evenly
           above and below the frame. Based on the screen height with the toolbar
           showing, which does not change while scrolling.
           400px = 330 rows and lines + 70 three-line footer */
        padding-top: max(20px, calc((100svh - 400px - min(100vw - 40px, 380px)) / 2));
    }
}

/* Frame: one lined box holding the cover and the links */
.frame {
    width: 100%;
    max-width: 380px;
    border: 2px solid #111111;
}

/* Short, wide windows (laptops, landscape phones): the frame also yields to the
   window height, so the whole page fits with the footer in view.
   410px = 330 rows and lines + 40 container padding + 38 footer + 2 spare.
   Adding or removing a link row changes it by 50 */
@media (min-width: 640px) {
    .frame {
        max-width: clamp(280px, calc(100vh - 410px), 380px);
        max-width: clamp(280px, calc(100svh - 410px), 380px);
    }
}

/* The title printed on the photo starts 3.26% in from its edge. Where the
   browser can measure the frame, the inset follows it, so logos, labels and the
   hover bar's text stay under that title at every frame width (12px at full
   size, 9px on the narrowest frame). Other browsers keep 12px */
@supports (width: round(1cqi, 1px)) {
    .frame {
        container-type: inline-size;
        --inset: clamp(9px, round(3.26cqi, 1px), 12px);
    }
}

.frame-row {
    display: flex;
    font-size: 0.7rem;
    line-height: 1rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.05em;
}

.frame-row span {
    padding: 6px var(--inset);
}

.frame-row span:first-child {
    flex: 1;
}

/* Right-hand cell: the shared column plus its 2px divider. The small indent
   balances the letter-spacing after the last digit, so the text is dead centre */
.frame-row span + span {
    flex: none;
    width: calc(var(--end) + 2px);
    padding: 6px 0;
    border-left: 2px solid #111111;
    text-align: center;
    text-indent: 0.05em;
}

.frame-bottom {
    border-top: 2px solid #111111;
}

/* The letter F carries about 1px of empty space on its left; this puts its
   stem on the same line as the logos above it */
.frame-bottom span:first-child {
    padding-left: calc(var(--inset) - 1px);
}

/* Album Artwork: edge to edge inside the frame. The cover carries the title and
   artist, so it is also the page heading, and links to YouTube */
.cover {
    position: relative;          /* holds the title bar, which sits over the picture */
    overflow: hidden;
    overflow: clip;
    border-bottom: 2px solid #111111;
    /* Only seen if the picture fails to load: its description as a small label */
    font-size: 0.7rem;
    line-height: 1rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.05em;
}

.cover a {
    display: block;
    position: relative;
    overflow: hidden;
    overflow: clip;              /* same clipping, but the box can never be scrolled */
    background-color: #506e48;   /* the photo's average colour, shown until it arrives */
    color: #ffffff;
    text-decoration: none;
}

.cover picture {
    display: block;
    flex-shrink: 0;
}

.cover img {
    display: block;
    width: 100%;
    height: auto;
    aspect-ratio: 1 / 1;
}

/* While the opening run of pictures plays, the album cover waits underneath */
.cover-cycle .cover-img {
    opacity: 0;
}

/* Transitions (assets/js/transitions.js): each picture, piece or canvas is a
   layer laid over the box, then removed */
.fx-box {
    position: relative;
}

.fx-box > .fx-layer {
    position: absolute;
    inset: 0;
    display: block;
    width: 100%;
    height: 100%;
    object-fit: cover;
}

/* A cut-out rectangle; the picture inside may be zoomed so nested ones read
   as separate prints */
.fx-box .fx-piece > img {
    display: block;
    width: 100%;
    height: 100%;
    object-fit: cover;
}

/* The lined border that opens out in the "mat" transition */
.fx-mat {
    position: absolute;
    border: 2px solid #111111;
    pointer-events: none;
}

/* The 2px line that leads a "line-wipe" */
.fx-line {
    position: absolute;
    background-color: #111111;
    pointer-events: none;
}

.fx-line-v {
    top: 0;
    bottom: 0;
    width: 2px;
    margin-left: -1px;
}

.fx-line-h {
    left: 0;
    right: 0;
    height: 2px;
    margin-top: -1px;
}

/* Camera shutter blades and the photo flash */
.fx-panel {
    position: absolute;
    left: 0;
    right: 0;
    height: 50%;
    background-color: #111111;
}

.fx-panel-top {
    top: 0;
    transform-origin: top;
}

.fx-panel-bottom {
    bottom: 0;
    transform-origin: bottom;
}

.fx-flash {
    position: absolute;
    inset: 0;
    background-color: #ffffff;
    opacity: 0;
    pointer-events: none;
}

/* Film grain over the cover: barely there, it reads as texture, not movement */
.cover-grain {
    position: absolute;
    inset: 0;
    background-size: 96px 96px;
    pointer-events: none;
}

/* Keyboard focus: a black line with a white partner inside it, so the ring
   shows on light and dark parts of the photo alike. Drawn on its own layer so
   it closes 2px above the title bar (30px tall) instead of running under it */
.cover a:focus-visible {
    outline: none;
}

.cover a:focus-visible::before {
    content: "";
    position: absolute;
    inset: 2px 2px 32px;
    border: 2px solid #111111;
    outline: 2px solid #ffffff;
    outline-offset: -4px;
    pointer-events: none;
    z-index: 1;                  /* above the pictures of the opening run */
}

/* Hover bar: a small lined label with the album title. It slides up over the
   bottom of the cover as one piece and stops at its own height. It sits on the
   line under the cover, so every line keeps the same 2px weight and nothing
   below moves. It is not part of the link, so its text can be selected */
.cover-bar {
    position: absolute;
    left: 0;
    right: 0;
    bottom: 0;
    background-color: #ffffff;
    color: #111111;
    border-top: 2px solid #111111;
    transform: translateY(100%);
    visibility: hidden;          /* not findable or selectable while out of view */
    z-index: 1;
    cursor: text;
}

.cover a:focus-visible + .cover-bar,
.cover a:active + .cover-bar,
.cover.is-selecting .cover-bar {
    transform: none;
    visibility: visible;
}

/* Hover only where there is a real pointer, so it never sticks after a tap.
   The whole cover counts, so the bar stays open while the pointer is on it */
@media (hover: hover) and (pointer: fine) {
    .cover:hover .cover-bar {
        transform: none;
        visibility: visible;
    }
}

/* Artist: the full name across the frame, white on a dark row the height of
   a link row */
.artist {
    padding: 15px var(--inset);
    background-color: #111111;
    color: #ffffff;
    border-bottom: 2px solid #111111;
}

/* Selected text on the dark row inverts the other way */
.artist ::selection {
    background-color: rgba(255, 255, 255, 0.99);
    color: #111111;
}

/* The name in the frame's own lettering (spaced capitals, like the name printed
   on the cover), sized to run edge to edge on one line. The negative margin
   takes back the spacing after the last letter, so it ends on the inset line.
   A fixed line height keeps the row 48px whatever size the name becomes */
.artist-name {
    display: block;
    width: max-content;
    white-space: nowrap;
    margin-right: -0.08em;
    font-size: 0.8rem;
    font-weight: 700;
    line-height: 18px;
    text-transform: uppercase;
    letter-spacing: 0.08em;
}

/* Where the frame can be measured, CSS sets the size from its width (the name
   is about 19.3 times its font size wide); a small script in the page then
   corrects it for the visitor's own font */
@supports (width: round(1cqi, 1px)) {
    .artist-name {
        font-size: calc((100cqi - 2 * var(--inset)) / 19.3);
    }
}

/* Links: lined rows. The lines are 2px gaps that let the dark background show,
   so every row is the same 48px box and its focus ring sits evenly inside it */
.links {
    display: flex;
    flex-direction: column;
    gap: 2px;
    background-color: #111111;
}

.btn {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 14px 0 14px var(--inset);   /* no right padding: the arrow box is the right-hand column */
    background-color: #ffffff;
    color: #111111;
    text-decoration: none;
    font-weight: 600;
}

/* Brand logos: solid shapes that take the row's text colour */
.icon {
    display: block;
    width: 20px;
    height: 20px;
    flex-shrink: 0;
    fill: currentColor;
}

/* Bandcamp's mark is much lower than the others, so it is drawn larger. The
   margins keep its 20px slot and put its left tip on the same line as the rest */
.icon-bandcamp {
    width: 24px;
    height: 24px;
    margin: -2px -4px -2px 0;
}

/* Trim the label's box to its capital letters so the row centres
   the letters themselves against the icon, not the font's line box */
.label {
    flex: 1;
    line-height: 1.2;
    text-box: trim-both cap alphabetic;
}

/* Arrow, drawn as a shape so it centres the same way in every font.
   2px stroke: the weight of the lines, and crisp on ordinary screens.
   Its box is the right-hand column, with the 16px arrow centred in it */
.btn::after {
    content: "";
    width: var(--end);
    height: 16px;
    flex-shrink: 0;
    background-color: currentColor;
    -webkit-mask: var(--arrow) center / 16px 16px no-repeat;
    mask: var(--arrow) center / 16px 16px no-repeat;
}

.btn:active,
.btn:focus-visible {
    background-color: #111111;
    color: #ffffff;
}

.btn:focus-visible {
    outline: 2px solid #ffffff;
    outline-offset: -6px;
}

/* The arrow steps toward where the link goes: once on hover or focus, twice on press */
.btn:focus-visible::after {
    transform: translateX(3px);
}

/* Hover only where there is a real pointer, so it never sticks after a tap */
@media (hover: hover) and (pointer: fine) {
    .btn:hover {
        background-color: #111111;
        color: #ffffff;
    }

    .btn:hover::after {
        transform: translateX(3px);
    }
}

.btn:active::after {
    transform: translateX(5px);
}

/* Footer: a full-width line at the bottom of the page */
footer {
    padding: 10px var(--inset);
    border-top: 2px solid #111111;
    text-align: center;
    font-size: 0.7rem;
    line-height: 1rem;
    text-transform: uppercase;
    letter-spacing: 0.05em;
}

/* Phones: one part per line, so nothing breaks in the middle of a name */
footer span {
    display: block;
}

footer .dot {
    display: none;
}

@media (min-width: 640px) {
    footer span,
    footer .dot {
        display: inline;
    }
}

/* Windows contrast themes replace backgrounds with system colours, which would
   hide the arrows (drawn with a background) and the black hover state. The
   arrows get a system colour, and hover, focus and press underline the label */
@media (forced-colors: active) {
    /* The gap lines rely on a background, so real borders take their place */
    .links {
        gap: 0;
    }

    .btn:not(:last-child) {
        border-bottom: 2px solid CanvasText;
    }

    .btn::after {
        background-color: LinkText;
    }

    .btn:active .label,
    .btn:focus-visible .label {
        text-decoration: underline;
    }
}

@media (forced-colors: active) and (hover: hover) and (pointer: fine) {
    .btn:hover .label {
        text-decoration: underline;
    }
}

/* All movement lives here: visitors who ask for reduced motion get none of it */
@media (prefers-reduced-motion: no-preference) {
    /* Cover bar: leaves quickly, arrives a little slower and settles.
       It only becomes hidden once it has slid away */
    .cover-bar {
        transition: transform 0.14s cubic-bezier(0.4, 0, 1, 1), visibility 0s 0.14s;
    }

    /* A pointer that only crosses the cover does not flick the bar up: it waits a moment */
    .cover:hover .cover-bar {
        transition: transform 0.2s cubic-bezier(0.2, 0, 0, 1) 0.07s, visibility 0s 0.07s;
    }

    .cover a:focus-visible + .cover-bar,
    .cover a:active + .cover-bar,
    .cover.is-selecting .cover-bar {
        transition: transform 0.2s cubic-bezier(0.2, 0, 0, 1), visibility 0s;
    }

    /* Rows: only the background fades. The text, logo and arrow flip colour
       part-way instead of fading through the same grey as the background */
    .btn {
        transition: background-color 0.18s ease-out, color 0s 0.06s;
    }

    .btn:hover,
    .btn:focus-visible {
        transition: background-color 0.06s linear, color 0s 0.03s;
    }

    /* A press shows at once */
    .btn:active {
        transition: none;
    }

    .btn::after {
        transition: transform 0.18s cubic-bezier(0.2, 0, 0, 1);
    }
}
