/* ==========================================================================
   MyLyricsFinder

   Palette from the logo. favicon.ico is a solid #FF6510 disc carrying an
   off-white note, so the site is that orange over warm near-black, with the
   note's off-white as the text colour. Warm neutrals, not the cool navy this
   file used to open with — orange over a cool ground fights rather than sits.

   The organising principle is artwork. 751 of 752 songs have cover art, and a
   site about music that shows none of it reads as a text file. Every song row,
   card and header leads with the image; the song's own art, blurred, becomes
   the atmosphere of its page.
   ========================================================================== */

/* --- Tokens -------------------------------------------------------------- */

:root {
    /* Taken from favicon.ico: a solid #FF6510 disc carrying an off-white
       note. Two colours, no secondary — so the palette is the logo orange
       against warm neutrals, and the off-white becomes the text colour.

       The neutrals are warm on purpose. The previous base was a cool navy
       (#0F0F23), and a warm orange over a cool ground reads as a collision
       rather than a choice. Shifting the greys warm lets the orange sit in
       the page instead of vibrating against it. */

    --bg:            #12100E;
    --bg-deep:       #0B0A09;
    --surface:       #1C1917;
    --surface-2:     #262220;
    --surface-3:     #332D2A;

    --fg:            #FBF8F5;   /* the note in the logo, near enough */
    --fg-muted:      #B5AAA2;
    --fg-dim:        #857A73;

    --brand:         #FF6510;   /* the logo, exactly */
    --brand-bright:  #FF8940;   /* hover, and text on darker surfaces */
    --brand-deep:    #C8480A;   /* pressed, and borders that need to recede */

    /* Text ON a brand fill. White fails here: #FFF on #FF6510 is 2.95:1,
       under the 4.5:1 floor and under even the 3:1 large-text floor. Orange
       is bright enough that its accessible partner is near-black (6.5:1),
       which is why no button in this file puts white on the brand colour. */
    --on-brand:      #1A0B02;

    /* Gold, analogous to the logo rather than a second brand. Marks a song
       that has a reading. Green would have been the obvious pick and the
       wrong one: it is the only cool hue left and it fights everything. */
    --accent:        #F5B841;

    --border:        #35302C;
    --border-soft:   #262220;

    /* Newsreader stays: it is a variable serif with an optical-size axis, so
       it holds its proportions from a 12px label to a 60px pull-quote, and it
       has enough character to carry the editorial voice.

       Roboto did not stay. It is the most-used sans on the web and it reads
       as the absence of a decision — which on a page whose whole claim is
       close reading is the wrong thing to say. Inter is drawn for text at
       small sizes, has true tabular figures for the timecodes and chart
       numbers, and ships as one variable file instead of Roboto's four
       static weights, so it is also less to download. */
    --display: 'Newsreader', Georgia, serif;
    --body:    'Inter', system-ui, -apple-system, 'Segoe UI', sans-serif;
    --mono:    'IBM Plex Mono', ui-monospace, Menlo, monospace;

    --t-xs:   0.75rem;
    --t-sm:   0.875rem;
    --t-base: 1rem;
    --t-md:   1.0625rem;
    --t-lg:   clamp(1.25rem, 1.1rem + 0.7vw, 1.6rem);
    --t-xl:   clamp(1.75rem, 1.4rem + 1.6vw, 2.6rem);
    --t-2xl:  clamp(2.25rem, 1.6rem + 3vw, 3.75rem);

    --measure: 38rem;
    --gutter: clamp(1rem, 3.5vw, 2.5rem);
    --rhythm: clamp(3rem, 6vw, 5rem);

    --r-sm: 6px;
    --r-md: 10px;
    --r-lg: 16px;

    --shadow-1: 0 1px 2px rgba(0,0,0,.4);
    --shadow-2: 0 4px 16px rgba(0,0,0,.45);
    --shadow-3: 0 12px 40px rgba(0,0,0,.55);

    --ease: cubic-bezier(0.2, 0.6, 0.2, 1);
    --fast: 180ms;
    --med: 260ms;
}

/* --- Reset --------------------------------------------------------------- */

*, *::before, *::after { box-sizing: border-box; }

html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth; }

@media (prefers-reduced-motion: reduce) {
    html { scroll-behavior: auto; }
    *, *::before, *::after {
        animation-duration: 0.01ms !important;
        animation-iteration-count: 1 !important;
        transition-duration: 0.01ms !important;
    }
}

body {
    margin: 0;
    background: var(--bg);
    color: var(--fg);
    font-family: var(--body);
    font-size: var(--t-base);
    line-height: 1.6;
    -webkit-font-smoothing: antialiased;
}

img { max-width: 100%; display: block; }
h1, h2, h3, h4 { margin: 0; line-height: 1.15; font-weight: 600; }
p { margin: 0 0 1em; }
a { color: inherit; text-decoration: none; }

/* Two rings, not one. A single orange ring vanished against the primary
   button, which is now orange too — 1.25:1, so keyboard users lost the focus
   indicator on the most important control on the page. The inner ring is
   near-black (6.5:1 on the brand fill) and the outer is off-white (17.9:1 on
   the page), so whichever surface focus lands on, one of the two is legible. */
:focus-visible {
    outline: 2px solid var(--fg);
    outline-offset: 2px;
    box-shadow: 0 0 0 2px var(--on-brand);
    border-radius: var(--r-sm);
}

::selection { background: var(--brand-bright); color: var(--on-brand); }

.visually-hidden {
    position: absolute !important;
    width: 1px; height: 1px;
    padding: 0; margin: -1px;
    overflow: hidden; clip: rect(0,0,0,0);
    white-space: nowrap; border: 0;
}

.skip {
    position: absolute; left: -9999px; top: 0;
    background: var(--brand-bright); color: var(--on-brand);
    padding: .75rem 1.25rem; z-index: 200;
    font-weight: 500; border-radius: 0 0 var(--r-sm) 0;
}
.skip:focus { left: 0; top: 0; }

/* --- Layout -------------------------------------------------------------- */

.wrap {
    width: min(78rem, 100% - (var(--gutter) * 2));
    margin-inline: auto;
}

.wrap--narrow { width: min(48rem, 100% - (var(--gutter) * 2)); }

.band { padding-block: var(--rhythm); }

/* Two bands in a row paid the rhythm twice — one band's bottom padding plus
   the next one's top — so the homepage carried 160px of empty black between
   its two sections and read as though the page had ended. One gap between
   two sections, not two. */
.band + .band { padding-top: 0; }

/* A masthead rule under every section title.
 *
 * The two sections were set at the same size with nothing between them and
 * the content, so the page had no visible structure — it read as one long
 * scroll of cards. A hairline is the cheapest way to say "a new section
 * starts here", and it is the device the printed page has used for the
 * purpose for two centuries.
 */
.section-head {
    position: relative;
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 1rem;
    flex-wrap: wrap;
    margin-bottom: 1.75rem;
    padding-bottom: .85rem;
    border-bottom: 1px solid var(--border);
}

/* The rule starts in the brand and fades into the hairline.
   A grey rule under a grey heading is punctuation; a lit one is a masthead,
   and it costs nothing but the first few inches of the line. */
.section-head::after {
    content: '';
    position: absolute; left: 0; bottom: -1px;
    width: min(7rem, 40%); height: 2px;
    background: linear-gradient(90deg, var(--brand), rgba(255,101,16,0));
    border-radius: 2px;
}

.section-head h2 {
    font-family: var(--display);
    font-size: var(--t-lg);
    font-weight: 600;
    letter-spacing: -0.01em;
}

.section-head .meta {
    font-family: var(--body);
    font-size: var(--t-sm);
    color: var(--fg-muted);
    font-variant-numeric: tabular-nums;
}

.eyebrow {
    font-family: var(--mono);
    font-size: var(--t-xs);
    letter-spacing: .14em;
    text-transform: uppercase;
    color: var(--fg-dim);
    margin: 0 0 .75rem;
}

.timecode {
    display: inline-block;
    font-family: var(--mono);
    font-size: var(--t-xs);
    letter-spacing: .04em;
    color: var(--accent);
    background: rgba(245,184,65,.12);
    border: 1px solid rgba(245,184,65,.3);
    border-radius: 999px;
    padding: .2rem .6rem;
    font-variant-numeric: tabular-nums;
}

/* --- Header -------------------------------------------------------------- */

.site-head {
    position: sticky; top: 0; z-index: 50;
    background: rgba(18,16,14,.86);
    backdrop-filter: blur(14px);
    border-bottom: 1px solid var(--border-soft);
}

.site-head__inner {
    display: flex; align-items: center;
    gap: clamp(.75rem, 2.5vw, 2rem);
    min-height: 4rem;
}

.brand {
    display: flex; align-items: center; gap: .55rem;
    font-family: var(--display);
    font-size: 1.25rem; font-weight: 600;
    white-space: nowrap;
}

.brand__mark { flex: none; color: var(--brand); }
.brand__note { fill: var(--fg); }

.head-search {
    /* min-width:0, because a flex item defaults to min-width:auto and so
       refuses to shrink below its own contents. The input inside already had
       it; the form around it did not, so at 320px the icon, field and button
       added up to 323px and pushed every page into a horizontal scroll. */
    flex: 1 1 auto; min-width: 0; max-width: 30rem;
    display: flex; align-items: center; gap: .5rem;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: 999px;
    padding: .3rem .3rem .3rem .9rem;
    transition: border-color var(--fast) var(--ease), background var(--fast) var(--ease);
}

.head-search:focus-within { border-color: var(--brand-bright); background: var(--surface-2); }
.head-search svg { flex: none; color: var(--fg-dim); }

.head-search input {
    flex: 1; min-width: 0; border: 0; background: none;
    color: var(--fg); font-family: var(--body); font-size: var(--t-sm);
    padding: .5rem 0;
}
.head-search input::placeholder { color: var(--fg-dim); }
.head-search input:focus { outline: none; }

.head-search button {
    flex: none; border: 0; border-radius: 999px;
    min-height: 36px; padding: 0 1rem;
    background: var(--brand); color: var(--on-brand);
    font-family: var(--body); font-size: var(--t-sm); font-weight: 500;
    cursor: pointer;
    transition: background var(--fast) var(--ease);
}
.head-search button:hover { background: var(--brand-bright); }

.head-nav {
    display: flex; gap: 1.25rem;
    font-size: var(--t-sm); color: var(--fg-muted);
}
.head-nav a {
    display: inline-flex; align-items: center;
    min-height: 44px;
    transition: color var(--fast) var(--ease);
}
.head-nav a:hover { color: var(--fg); }

@media (max-width: 48rem) {
    .site-head__inner { flex-wrap: wrap; padding-block: .6rem; row-gap: .6rem; }
    .head-search { order: 3; flex-basis: 100%; max-width: none; }
    .head-nav { margin-left: auto; }
}

/* --- Artwork ------------------------------------------------------------- */

/* Square by default, because a record is square.

   This used to default to 16/9 — the shape of a YouTube still, which is where
   the catalogue's art came from before covers were stored. 668 of 768 songs
   now carry a real album cover, so the exception was setting the rule: square
   covers and widescreen video stills sat in the same grid at different shapes
   and the page read as two designs sharing a page. One shape everywhere, and
   the remaining stills are cropped to it by object-fit below. */
.art {
    position: relative;
    display: block;
    aspect-ratio: 1;
    overflow: hidden;
    border-radius: var(--r-md);
    background: var(--surface-2);
}

.art img {
    width: 100%; height: 100%;
    object-fit: cover;
    transition: transform var(--med) var(--ease);
}

/* Kept for anything that genuinely is widescreen — a video still standing on
   its own rather than sitting in a grid of covers. */
.art--wide { aspect-ratio: 16 / 9; }
.art--square { aspect-ratio: 1; }

/* A placeholder that still reads as a record rather than a broken image. */
.art--empty {
    display: grid; place-items: center;
    color: var(--fg-dim);
    background: linear-gradient(140deg, var(--surface-2), var(--surface));
}

/* --- Hero ---------------------------------------------------------------- */

.hero {
    position: relative;
    padding-block: clamp(2.5rem, 6vw, 4.5rem) clamp(2rem, 4vw, 3rem);
    overflow: hidden;
}

/* The hero already ends with breathing room, so the first band after it does
   not need a full rhythm on top as well. */
.hero + .band { padding-top: clamp(2rem, 4vw, 3rem); }

/* The song's own artwork becomes the atmosphere of the page. */
.hero__backdrop {
    position: absolute;
    inset: -20%;
    z-index: 0;
    background-size: cover;
    background-position: center;
    filter: blur(60px) saturate(160%);
    opacity: .3;
    transform: scale(1.1);
}

.hero__scrim {
    position: absolute; inset: 0; z-index: 1;
    background:
        linear-gradient(180deg, rgba(18,16,14,.55) 0%, rgba(18,16,14,.9) 70%, var(--bg) 100%);
}

.hero__inner {
    position: relative; z-index: 2;
    display: grid;
    gap: clamp(1.5rem, 4vw, 3rem);
    align-items: center;
    grid-template-columns: minmax(0, 1fr);
}

@media (min-width: 56rem) {
    .hero__inner { grid-template-columns: minmax(0, 26rem) minmax(0, 1fr); }
}

/* Square, like every other piece of art on the site, and like a record.
   This was the last 16/9 box left once the grids went square, so the one
   image the page is built around was the one image the wrong shape. */
.hero__art {
    border-radius: var(--r-lg);
    box-shadow: var(--shadow-3);
    overflow: hidden;
    aspect-ratio: 1;
    background: var(--surface-2);
}

.hero__art img { width: 100%; height: 100%; object-fit: cover; }

.hero__quote {
    font-family: var(--display);
    font-size: var(--t-2xl);
    font-weight: 500;
    line-height: 1.15;
    margin: .85rem 0 1rem;
    text-wrap: balance;
}

.hero__reading {
    font-size: var(--t-md);
    color: var(--fg-muted);
    max-width: var(--measure);
    margin: 0 0 1.5rem;
}

.hero__meta {
    display: flex; align-items: center; gap: .75rem;
    flex-wrap: wrap;
    font-size: var(--t-sm);
    color: var(--fg-muted);
    margin: 0 0 1.5rem;
}

.hero__meta strong { color: var(--fg); font-weight: 600; }

/* --- Buttons ------------------------------------------------------------- */

.btn {
    display: inline-flex; align-items: center; justify-content: center;
    gap: .5rem;
    min-height: 44px;
    padding: 0 1.25rem;
    border: 1px solid var(--border);
    border-radius: 999px;
    background: var(--surface-2);
    color: var(--fg);
    font-family: var(--body); font-size: var(--t-sm); font-weight: 500;
    cursor: pointer;
    transition: background var(--fast) var(--ease), border-color var(--fast) var(--ease), transform var(--fast) var(--ease);
}

.btn:hover { background: var(--surface-3); border-color: var(--brand-bright); }
.btn:active { transform: scale(.98); }

.btn--primary {
    background: var(--brand);
    border-color: var(--brand);
    color: var(--on-brand);
}
.btn--primary:hover { background: var(--brand-bright); border-color: var(--brand-bright); }

.btn[disabled] { opacity: .45; cursor: not-allowed; }
.btn[disabled]:hover { background: var(--surface-2); border-color: var(--border); }

/* --- Song cards (grid) --------------------------------------------------- */

.card-grid {
    display: grid;
    gap: clamp(1rem, 2vw, 1.5rem);
    grid-template-columns: repeat(auto-fill, minmax(15rem, 1fr));
}

/* A card should read as an object sitting on the page.
 *
 * Surface (#1C1917) against ground (#12100E) is four points of luminance —
 * technically a difference, visually nothing, so twelve cards read as one
 * grey field. A gradient gives the face a top-lit direction, and a hairline
 * of light along the top edge is what separates a physical object from a
 * painted rectangle. */
.card {
    display: flex; flex-direction: column;
    position: relative;
    background: linear-gradient(168deg, var(--surface-2) 0%, var(--surface) 58%);
    border: 1px solid var(--border);
    border-radius: var(--r-md);
    overflow: hidden;
    box-shadow: var(--shadow-1);
    transition: transform var(--fast) var(--ease),
                border-color var(--fast) var(--ease),
                box-shadow var(--fast) var(--ease);
}

/* The lit top edge. */
.card::after {
    content: '';
    position: absolute; inset: 0 0 auto 0; height: 1px;
    background: linear-gradient(90deg, transparent, rgba(255,255,255,.10) 22%, rgba(255,255,255,.10) 78%, transparent);
    pointer-events: none;
}

/* On hover the card is lit from its own artwork's side of the palette rather
   than just outlined: a warm cast under it, so the wall of covers reacts. */
.card:hover {
    transform: translateY(-4px);
    border-color: var(--brand-deep);
    box-shadow:
        0 18px 40px -12px rgba(0,0,0,.7),
        0 0 0 1px rgba(255,101,16,.35),
        0 12px 46px -14px rgba(255,101,16,.45);
}

.card:hover .art img { transform: scale(1.05); }

.card__body { padding: .9rem 1rem 1.1rem; }

.card__track {
    font-family: var(--display);
    font-size: var(--t-md);
    font-weight: 600;
    line-height: 1.25;
    margin: 0 0 .2rem;
    /* Wrap to two lines, then ellipsis — a truncated title is worse than two lines. */
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
    /* Both lines are reserved whether or not the second is used. Without it a
       one-line title sat a line higher than its neighbours, so the artist and
       the "Interpreted" flag stepped up and down across the grid and the row
       had no baseline to read along. 2 lines x 1.25 line-height. */
    min-height: 2.5em;
}

/* Block, not inline: as spans these ran together on one line —
   "Nickelback ✓ Interpreted" instead of two stacked lines. */
.card__artist {
    display: block;
    font-size: var(--t-sm);
    color: var(--fg-muted);
    margin: 0;
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}

/* A badge, not a line of small grey text.
 *
 * "Interpreted" is the single most useful thing on a card — it is the whole
 * proposition of the site, and it was set at 12px in the dimmest grey
 * available, indistinguishable at a glance from "Not yet read". A filled pill
 * makes the state readable from across the grid without reading a word. */
.card__flag {
    display: inline-flex; align-items: center; gap: .35rem;
    align-self: flex-start;
    margin-top: .6rem;
    padding: .2rem .55rem;
    font-size: var(--t-xs);
    font-weight: 500;
    line-height: 1.5;
    border-radius: 999px;
    /* fg-muted, not fg-dim. Putting a lit surface behind the text raised the
       effective background and dropped this to 4.17:1 — under the floor. The
       pill is the readable version of the badge, so it cannot be the one that
       fails; the brighter grey measures well clear. */
    color: var(--fg-muted);
    background: rgba(255,255,255,.04);
    border: 1px solid var(--border);
}

.card__flag--read {
    color: var(--accent);
    background: rgba(245,184,65,.12);
    border-color: rgba(245,184,65,.34);
}

/* --- Song rows (compact list) -------------------------------------------- */

.row-list { display: flex; flex-direction: column; gap: .25rem; }

/* The browser's own [hidden] rule is only `display: none` at user-agent
   weight, so any class here that sets display -- .row does, below -- silently
   overrides it and the element stays on screen with the attribute set. The
   chart list's reveal-on-scroll hides rows exactly that way, so this makes
   `hidden` mean hidden regardless of what a component sets. */
[hidden] { display: none !important; }

/* Scroll marker for the reveal-on-scroll list. It has to occupy a little
   height, or it can never intersect the viewport and the next rows never
   arrive. */
.row-list__sentinel { height: 1px; margin-top: .25rem; }

.row {
    display: grid;
    grid-template-columns: 2.25rem 3.5rem minmax(0,1fr) auto;
    align-items: center;
    gap: 1rem;
    padding: .6rem .75rem;
    border-radius: var(--r-md);
    min-height: 64px;
    /* A hairline between entries rather than nothing: an index reads as a
       list, and the rules are what make the rhythm visible when the art is
       dark and the rows blur together. */
    box-shadow: inset 0 -1px 0 var(--border-soft);
    transition: background var(--fast) var(--ease);
}

.row-list > .row:last-child { box-shadow: none; }

.row:hover { background: var(--surface); }

/* The rank, set as a graphic rather than a footnote.
 *
 * A chart is a ranking, and the number is the reason the list is in this
 * order — it was 12px in the dimmest grey on the page, carrying none of that.
 * Brand orange on the ground measures 6.4:1, so this is loud and still legible
 * well past the 4.5:1 floor. */
.row__num {
    font-family: var(--mono);
    font-size: var(--t-md);
    font-weight: 500;
    color: var(--brand);
    font-variant-numeric: tabular-nums;
    text-align: right;
    letter-spacing: -0.02em;
}

/* The art in a row was pinned to 16/9 here, which outranked the art--square
   the markup actually asked for: the chart index rendered postage-stamp
   widescreen thumbnails in a page of square covers. Only the corner radius
   belongs at this size. */
.row .art { border-radius: var(--r-sm); }

/* The text column of a row.
 *
 * min-width:0 is what lets the truncation below actually happen: a grid item
 * defaults to min-width:auto, which refuses to shrink past its content, so
 * the column grows instead of the text clipping. It was an inline style on
 * three templates; it is a rule about the layout, so it lives here.
 */
.row__text { min-width: 0; }

/* display:block is load-bearing, not tidying. These are spans, and overflow,
   text-overflow and white-space do nothing to a non-replaced inline box — so
   the truncation below was inert and a long title simply ran past its grid
   column. On a 390px phone that pushed the document to 816px and the whole
   page scrolled sideways. */
.row__track {
    display: block;
    font-weight: 500; font-size: var(--t-base);
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}

.row__artist {
    display: block;
    font-size: var(--t-sm); color: var(--fg-muted);
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}

.row__meta { font-size: var(--t-xs); color: var(--fg-dim); white-space: nowrap; }

@media (max-width: 34rem) {
    .row { grid-template-columns: 1.5rem 3rem minmax(0,1fr); gap: .8rem; }
    .row__meta { display: none; }
}

/* --- Song page ----------------------------------------------------------- */

.song-hero {
    position: relative;
    overflow: hidden;
    padding-block: clamp(2rem, 5vw, 3.5rem);
    border-bottom: 1px solid var(--border-soft);
}

.song-hero__inner {
    position: relative; z-index: 2;
    display: grid;
    gap: clamp(1.25rem, 3vw, 2.5rem);
    align-items: end;
    grid-template-columns: minmax(0, 1fr);
}

@media (min-width: 48rem) {
    .song-hero__inner { grid-template-columns: minmax(0, 20rem) minmax(0, 1fr); }
}

/* Square, matching the homepage hero and every grid on the site. Left at
   16/9 this was the one page where the song's own art changed shape. */
.song-hero__art {
    border-radius: var(--r-lg);
    overflow: hidden;
    box-shadow: var(--shadow-3);
    aspect-ratio: 1;
    background: var(--surface-2);
}

.song-hero__art img { width: 100%; height: 100%; object-fit: cover; }

.song-hero__title {
    font-family: var(--display);
    font-size: var(--t-xl);
    font-weight: 600;
    margin: .5rem 0 .35rem;
    text-wrap: balance;
}

.song-hero__artist {
    font-size: var(--t-md);
    color: var(--fg-muted);
    margin: 0 0 1.25rem;
}

.song-hero__actions { display: flex; gap: .6rem; flex-wrap: wrap; }

.song-grid {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    gap: clamp(2rem, 4vw, 3rem);
    padding-block: var(--rhythm);
}

@media (min-width: 62rem) {
    .song-grid { grid-template-columns: minmax(0, 1fr) minmax(0, 21rem); }
}

.panel {
    background: var(--surface);
    border: 1px solid var(--border-soft);
    border-radius: var(--r-md);
    padding: 1.25rem;
}

.panel__label {
    display: flex; align-items: center; justify-content: space-between;
    gap: .75rem;
    font-size: var(--t-sm); font-weight: 600;
    color: var(--fg);
    padding-bottom: .75rem;
    margin-bottom: .9rem;
    border-bottom: 1px solid var(--border-soft);
}

.panel__label span { font-size: var(--t-xs); color: var(--fg-dim); font-weight: 400; }

.video-frame {
    position: relative; aspect-ratio: 16/9;
    border-radius: var(--r-md); overflow: hidden;
    background: #000; margin-bottom: 1.25rem;
    box-shadow: var(--shadow-2);
}
.video-frame iframe { position: absolute; inset: 0; width: 100%; height: 100%; border: 0; }

/* Lyrics */
.lyrics-sync-container {
    max-height: 26rem; overflow-y: auto;
    padding-right: .5rem;
    scrollbar-width: thin;
    scrollbar-color: var(--surface-3) transparent;
}

.lyrics-line {
    padding: .45rem .6rem;
    border-radius: var(--r-sm);
    color: var(--fg-muted);
    font-size: var(--t-sm);
    line-height: 1.5;
    cursor: pointer;
    transition: background var(--fast) var(--ease), color var(--fast) var(--ease);
}

.lyrics-line:hover { background: var(--surface-2); color: var(--fg); }

.lyrics-line.is-current {
    background: rgba(245,184,65,.12);
    color: var(--fg);
    font-weight: 500;
    box-shadow: inset 3px 0 0 var(--accent);
}

.lyrics-plain {
    max-height: 26rem; overflow-y: auto;
    padding-right: .5rem;
    font-size: var(--t-sm); line-height: 1.75;
    color: var(--fg-muted);
    white-space: pre-wrap; margin: 0;
}

/* The reading */
.reading__question {
    font-family: var(--display);
    font-size: var(--t-lg);
    font-weight: 600;
    margin-bottom: 1.25rem;
    text-wrap: balance;
}

.reading__body {
    font-family: var(--display);
    font-size: var(--t-md);
    line-height: 1.75;
    max-width: var(--measure);
    color: var(--fg);
}

.reading__body p { margin: 0 0 1.1em; }

.reading__subhead {
    font-family: var(--display);
    font-size: var(--t-md);
    font-style: italic;
    font-weight: 400;
    color: var(--fg-muted);
    margin: 0 0 1.1em;
}

.reading__byline {
    display: flex; align-items: center; gap: .6rem; flex-wrap: wrap;
    margin-top: 1.5rem; padding-top: 1rem;
    border-top: 1px solid var(--border-soft);
    font-size: var(--t-sm); color: var(--fg-muted);
}

.reading + .reading { margin-top: 2rem; padding-top: 2rem; border-top: 1px solid var(--border-soft); }

.badge {
    display: inline-flex; align-items: center; gap: .3rem;
    border-radius: 999px; padding: .2rem .65rem;
    font-size: var(--t-xs); font-weight: 500;
    background: var(--surface-2); color: var(--fg-muted);
    border: 1px solid var(--border);
}

.badge--editorial {
    background: rgba(255,101,16,.18);
    border-color: var(--brand);
    color: var(--brand-bright);
}

/* --- Search -------------------------------------------------------------- */

.search-hero { padding-block: clamp(2rem, 5vw, 3.5rem) 1.5rem; }

.search-hero h1 {
    font-family: var(--display);
    font-size: var(--t-xl);
}

.search-form-lg { display: flex; gap: .6rem; margin-top: 1.25rem; max-width: 36rem; flex-wrap: wrap; }

.search-form-lg input {
    flex: 1 1 14rem; min-width: 0;
    background: var(--surface); border: 1px solid var(--border);
    color: var(--fg); font-family: var(--body); font-size: var(--t-md);
    padding: .75rem 1rem; border-radius: var(--r-md);
    min-height: 48px;
}
.search-form-lg input:focus { outline: none; border-color: var(--brand-bright); }
.search-form-lg input::placeholder { color: var(--fg-dim); }

/* --- Notices ------------------------------------------------------------- */

.notice {
    background: var(--surface);
    border: 1px solid var(--border);
    border-left: 3px solid var(--brand-bright);
    border-radius: var(--r-md);
    padding: 1rem 1.25rem;
    color: var(--fg-muted); font-size: var(--t-sm);
}
.notice strong { color: var(--fg); }

.pending {
    display: flex; align-items: center; gap: .6rem;
    color: var(--fg-muted); font-size: var(--t-sm);
}

.pending::before {
    content: ''; width: 8px; height: 8px; border-radius: 50%;
    background: var(--accent);
    animation: pulse 1.5s ease-in-out infinite;
}

@keyframes pulse { 0%,100% { opacity:.3 } 50% { opacity:1 } }

/* Skeleton for artwork that has not loaded. */
.skeleton {
    background: linear-gradient(90deg, var(--surface) 25%, var(--surface-2) 50%, var(--surface) 75%);
    background-size: 200% 100%;
    animation: shimmer 1.4s linear infinite;
}

@keyframes shimmer { to { background-position: -200% 0; } }

/* --- Prose --------------------------------------------------------------- */

.prose { font-family: var(--display); font-size: var(--t-md); line-height: 1.75; max-width: var(--measure); }
.prose p { margin: 0 0 1.15em; }

/* --- Modal --------------------------------------------------------------- */

.modal-content {
    background: var(--surface); border: 1px solid var(--border);
    color: var(--fg); border-radius: var(--r-lg);
}
.modal-header, .modal-footer { border-color: var(--border-soft) !important; }

.modal-content .form-control {
    background: var(--bg); border: 1px solid var(--border);
    color: var(--fg); border-radius: var(--r-sm); min-height: 44px;
}
.modal-content .form-control:focus {
    background: var(--bg); border-color: var(--brand-bright);
    color: var(--fg); box-shadow: none;
}
.modal-content .form-label { font-size: var(--t-sm); font-weight: 500; color: var(--fg); }
.modal-content .form-text { color: var(--fg-dim); font-size: var(--t-xs); }

/* --- Footer -------------------------------------------------------------- */

/* No margin-top. The last band already pays a full rhythm as its bottom
   padding, so adding another here stacked two — 160px of empty ground between
   the final row and the footer, which read as the page having ended early.
   The same double-count that sat between the two homepage sections; this was
   simply the other seam. The border and the change of ground are what
   separate the footer, not distance. */
.site-foot {
    border-top: 1px solid var(--border-soft);
    background: var(--bg-deep);
    padding-block: 2.5rem;
    color: var(--fg-muted); font-size: var(--t-sm);
}

/* The footer was a two-column flex that wrapped. At the width where it broke,
   the link list dropped under the fine print and the copyright was left
   floating with nothing to align to. Grid instead, so the columns are
   declared rather than emergent, and a separated bottom bar so the copyright
   always has a place to sit. */
.site-foot__top {
    display: grid;
    grid-template-columns: minmax(0, 1.2fr) minmax(0, 1fr);
    gap: clamp(2rem, 5vw, 4rem);
    align-items: start;
}

.site-foot__cols {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(10rem, 1fr));
    gap: clamp(1.5rem, 4vw, 2.5rem);
}

.site-foot__tag { font-family: var(--display); font-size: var(--t-md); color: var(--fg); margin: 0 0 .4rem; }

.site-foot__heading {
    font-family: var(--mono);
    font-size: var(--t-xs);
    font-weight: 500;
    letter-spacing: .14em;
    text-transform: uppercase;
    color: var(--fg-dim);
    margin: 0 0 .35rem;
}

.site-foot__list { list-style: none; margin: 0; padding: 0; }

.site-foot__list a {
    display: inline-flex; align-items: center; gap: .4rem;
    min-height: 40px;
    color: var(--fg-muted);
    transition: color var(--fast) var(--ease);
}

.site-foot__list a:hover { color: var(--brand-bright); }

/* The mark that says a link leaves the site, so "sister site" is shown and
   not only stated. Sized in em so it tracks the label. */
.site-foot__out {
    width: .7em; height: .7em;
    opacity: .55;
    flex: none;
}

.site-foot__list a:hover .site-foot__out { opacity: 1; }

.site-foot__bottom {
    margin-top: clamp(1.75rem, 4vw, 2.5rem);
    padding-top: 1.25rem;
    border-top: 1px solid var(--border-soft);
}

.site-foot__copy { margin: 0; font-size: var(--t-xs); color: var(--fg-dim); }

.site-foot__fine { font-size: var(--t-xs); color: var(--fg-dim); max-width: 34rem; margin: 0; }

@media (max-width: 46rem) {
    /* One column, brand block leading. Two link columns at this width left an
       orphaned word in each. */
    .site-foot__top { grid-template-columns: minmax(0, 1fr); gap: 2rem; }
}

/* --- Lyrics sizing ------------------------------------------------------- */

/* Was 0.875rem in a 21rem column, which is too small to read a lyric off.
   These override the earlier declarations deliberately. */
.panel--lyrics { padding: 1.25rem 1rem 1.25rem 1.25rem; }

.lyrics-sync-container,
.lyrics-plain {
    max-height: clamp(22rem, 52vh, 34rem);
    overscroll-behavior: contain;
}

.lyrics-line {
    font-size: var(--t-base);
    line-height: 1.65;
    padding: .5rem .7rem;
}

.lyrics-line.is-current { font-size: var(--t-md); }

.lyrics-plain {
    font-size: var(--t-base);
    line-height: 1.8;
    color: var(--fg);
}

/* A visible track, so it is obvious the panel scrolls. */
.lyrics-sync-container::-webkit-scrollbar,
.lyrics-plain::-webkit-scrollbar { width: 10px; }

.lyrics-sync-container::-webkit-scrollbar-track,
.lyrics-plain::-webkit-scrollbar-track { background: var(--bg); border-radius: 999px; }

.lyrics-sync-container::-webkit-scrollbar-thumb,
.lyrics-plain::-webkit-scrollbar-thumb {
    background: var(--surface-3);
    border-radius: 999px;
    border: 2px solid var(--bg);
}

.lyrics-sync-container::-webkit-scrollbar-thumb:hover,
.lyrics-plain::-webkit-scrollbar-thumb:hover { background: var(--brand); }

/* Fade the bottom edge so it reads as "more below" rather than a hard cut. */
.lyrics-wrap { position: relative; }

.lyrics-wrap::after {
    content: '';
    position: absolute; left: 0; right: 10px; bottom: 0; height: 3rem;
    background: linear-gradient(180deg, transparent, var(--surface));
    pointer-events: none;
    border-radius: 0 0 var(--r-md) var(--r-md);
}

/* --- Dialog -------------------------------------------------------------- */

/* Native <dialog> rather than a Bootstrap modal. The previous markup used
   Bootstrap's modal classes while the stylesheet no longer loaded Bootstrap,
   so the form rendered inline and unstyled on every song page. */
.dialog {
    width: min(38rem, calc(100vw - 2rem));
    padding: 0;
    border: 1px solid var(--border);
    border-radius: var(--r-lg);
    background: var(--surface);
    color: var(--fg);
    box-shadow: var(--shadow-3);
}

.dialog::backdrop {
    background: rgba(7, 6, 5, .74);
    backdrop-filter: blur(3px);
}

.dialog__head {
    display: flex; align-items: center; justify-content: space-between;
    gap: 1rem;
    padding: 1.1rem 1.25rem;
    border-bottom: 1px solid var(--border-soft);
}

.dialog__head h2 { font-family: var(--display); font-size: var(--t-lg); }

.dialog__close {
    display: inline-flex; align-items: center; justify-content: center;
    width: 44px; height: 44px;
    border: 0; border-radius: 50%;
    background: none; color: var(--fg-muted);
    cursor: pointer;
    transition: background var(--fast) var(--ease), color var(--fast) var(--ease);
}
.dialog__close:hover { background: var(--surface-2); color: var(--fg); }

.dialog__body { padding: 1.25rem; }
.dialog__foot {
    display: flex; justify-content: flex-end; gap: .6rem;
    padding: 1rem 1.25rem;
    border-top: 1px solid var(--border-soft);
}

.field { margin-bottom: 1.1rem; }

.field label {
    display: block;
    font-size: var(--t-sm); font-weight: 500;
    margin-bottom: .4rem;
}

.field input,
.field textarea {
    display: block; width: 100%;
    background: var(--bg);
    border: 1px solid var(--border);
    border-radius: var(--r-sm);
    color: var(--fg);
    font-family: var(--body); font-size: var(--t-base);
    padding: .7rem .85rem;
    min-height: 48px;
}

.field textarea { min-height: 11rem; resize: vertical; line-height: 1.6; }

.field input:focus,
.field textarea:focus { outline: none; border-color: var(--brand-bright); }

.field input::placeholder,
.field textarea::placeholder { color: var(--fg-dim); }

.field__hint {
    display: block;
    font-size: var(--t-xs); color: var(--fg-dim);
    margin-top: .35rem;
}

.form-message:empty { display: none; }

.form-message {
    border-radius: var(--r-sm);
    padding: .7rem .9rem;
    font-size: var(--t-sm);
    margin-bottom: .25rem;
}

.form-message--error { background: rgba(239,68,68,.12); border: 1px solid rgba(239,68,68,.4); color: #FCA5A5; }
.form-message--ok    { background: rgba(34,197,94,.12);  border: 1px solid rgba(34,197,94,.4);  color: #86EFAC; }
.form-message--busy  { background: var(--surface-2); border: 1px solid var(--border); color: var(--fg-muted); }

/* --- Lyrics search results ----------------------------------------------- */

.snippet {
    display: block;
    margin-top: .3rem;
    font-size: var(--t-sm);
    color: var(--fg-muted);
    line-height: 1.5;
    overflow: hidden;
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
}

.snippet mark {
    background: rgba(255,137,64,.28);
    color: var(--fg);
    border-radius: 3px;
    padding: 0 .15em;
}

.tabs {
    display: flex; gap: .4rem;
    margin-bottom: 1.25rem;
    border-bottom: 1px solid var(--border-soft);
}

.tabs a {
    display: inline-flex; align-items: center;
    min-height: 44px; padding: 0 .9rem;
    font-size: var(--t-sm); color: var(--fg-muted);
    border-bottom: 2px solid transparent;
    transition: color var(--fast) var(--ease), border-color var(--fast) var(--ease);
}

.tabs a:hover { color: var(--fg); }
.tabs a[aria-current="true"] { color: var(--fg); border-bottom-color: var(--brand-bright); font-weight: 500; }
.tabs .tabs__count { color: var(--fg-dim); margin-left: .4rem; font-size: var(--t-xs); }

/* ==========================================================================
   Vibrancy and reading rhythm

   Two problems this solves. The palette was faithful to the logo but flat:
   one orange against warm greys, used sparingly, so the page read as brown.
   And a 900-word reading arrived as one undifferentiated column, which is
   hard work on a phone.

   The orange does more work here, but only in places that are already
   interactive or already the focal point. Everything else stays quiet, so
   the brightness lands rather than shouting.
   ========================================================================== */

:root {
    --brand-glow: rgba(255, 101, 16, .32);
    --gold-glow:  rgba(245, 184, 65, .22);
}

/* A warm cast over the whole page, fixed so it does not travel on scroll.
   Cheap: one paint, no repaint while scrolling. */
/* Light in the room.
 *
 * The page was a flat near-black with two washes so faint they may as well
 * not have been there (.10 and .06). Everything read as grey text on grey,
 * and the only colour on screen was whatever the album covers brought.
 *
 * Three sources now, warm and asymmetric, so the ground has a direction and
 * a temperature instead of being a void: the logo orange from the top left,
 * the gold analogue from the right, and a deep pool at the foot so the page
 * closes rather than fading out. Fixed attachment, so scrolling moves the
 * content through the light rather than dragging the light along with it.
 */
body {
    background:
        radial-gradient(80rem 42rem at 8% -6%, rgba(255, 101, 16, .20), transparent 62%),
        radial-gradient(64rem 38rem at 96% 2%, rgba(245, 184, 65, .12), transparent 58%),
        radial-gradient(90rem 50rem at 50% 108%, rgba(200, 72, 10, .10), transparent 60%),
        var(--bg);
    background-attachment: fixed;
}

/* --- Eyebrows ------------------------------------------------------------ */

.eyebrow--accent {
    color: var(--brand-bright);
    display: flex; align-items: center; gap: .5rem;
}

.eyebrow--accent::before {
    content: '';
    width: 1.75rem; height: 2px; border-radius: 2px;
    background: linear-gradient(90deg, var(--brand), var(--accent));
}

/* --- Buttons ------------------------------------------------------------- */

.btn--primary {
    background: linear-gradient(135deg, #FF7D2B 0%, var(--brand) 55%, #F1560A 100%);
    border-color: transparent;
    box-shadow: 0 6px 18px var(--brand-glow);
}

.btn--primary:hover {
    background: linear-gradient(135deg, #FF9350 0%, var(--brand-bright) 55%, #FF6510 100%);
    border-color: transparent;
    box-shadow: 0 8px 26px var(--brand-glow);
    transform: translateY(-1px);
}

.btn--primary:active { transform: translateY(0); }

/* --- Cards --------------------------------------------------------------- */

.card:hover {
    border-color: var(--brand);
    box-shadow: 0 14px 34px rgba(0, 0, 0, .5), 0 0 0 1px var(--brand-glow);
}

.row:hover { border-color: var(--brand-deep); }

/* --- Hero ---------------------------------------------------------------- */

/* A warm bloom behind the artwork, so the top of the page has a light source
   instead of being uniformly dark. */
.hero, .song-hero { position: relative; isolation: isolate; }

.hero::after, .song-hero::after {
    content: '';
    position: absolute; inset: 0; z-index: 1;
    pointer-events: none;
    background: radial-gradient(48rem 26rem at 22% 42%, var(--brand-glow), transparent 68%);
    mix-blend-mode: screen;
    opacity: .55;
}

.song-hero__quote {
    font-family: var(--display);
    font-size: clamp(1.15rem, 1rem + 0.7vw, 1.55rem);
    font-style: italic;
    line-height: 1.4;
    color: var(--fg);
    margin: 0 0 1.4rem;
    max-width: 34rem;
    text-wrap: balance;
}

.song-hero__quote .timecode {
    font-style: normal;
    margin-right: .6rem;
    vertical-align: .12em;
}

/* --- The question -------------------------------------------------------- */

.reading__question {
    font-size: var(--t-xl);
    line-height: 1.12;
    margin: .5rem 0 1.75rem;
    max-width: 22ch;
}

/* --- The reading itself -------------------------------------------------- */

/* The opening paragraph carries the answer, so it is set larger. It is what a
   reader skims and what an answer engine quotes. */
.reading__body > p:first-of-type {
    font-size: clamp(1.1rem, 1.02rem + 0.35vw, 1.3rem);
    line-height: 1.62;
    color: var(--fg);
    margin-bottom: 1.6em;
}

.reading__body > p:first-of-type::first-letter {
    float: left;
    font-size: 3.4em;
    line-height: .82;
    padding: .06em .09em 0 0;
    color: var(--brand-bright);
    font-weight: 600;
}

/* Section headings. These used to be a muted italic line, because the only
   thing that ever appeared here was a subtitle the model added by mistake.
   They are real sections now, so they get real weight, and enough space above
   that they read as a break rather than as a caption. */
.reading__subhead {
    font-family: var(--display);
    font-size: clamp(1.2rem, 1.08rem + 0.5vw, 1.5rem);
    font-style: normal;
    font-weight: 600;
    color: var(--fg);
    line-height: 1.25;
    margin: 2.4rem 0 .9rem;
    padding-top: 1.4rem;
    border-top: 1px solid var(--border-soft);
    text-wrap: balance;
    position: relative;
}

.reading__subhead::before {
    content: '';
    position: absolute; top: -1px; left: 0;
    width: 3.5rem; height: 2px;
    background: linear-gradient(90deg, var(--brand), var(--accent));
}

/* The first heading follows the lead paragraph, so it needs less air. */
.reading__body > .reading__subhead:first-child {
    margin-top: 0; padding-top: 0; border-top: 0;
}

.reading__body > .reading__subhead:first-child::before { display: none; }

@media (max-width: 48rem) {
    .reading__body > p:first-of-type::first-letter {
        font-size: 2.9em;
    }
}

/* A sentence lifted verbatim from the paragraph beneath it, set large to break
   the column. Standard print practice, and the only structural relief
   available to the 748 readings written before the prompt asked for section
   headings. It repeats text by design, which is why it is aria-hidden. */
.reading__pull {
    font-family: var(--display);
    font-size: clamp(1.25rem, 1.05rem + 0.9vw, 1.7rem);
    font-style: italic;
    line-height: 1.35;
    color: var(--fg);
    margin: 2.2rem 0;
    padding: .2rem 0 .2rem 1.4rem;
    border-left: 3px solid;
    border-image: linear-gradient(180deg, var(--brand), var(--accent)) 1;
    text-wrap: balance;
}

/* The lyrics follow the reader down instead of leaving a column of empty page
   beside 900 words. */
@media (min-width: 62rem) {
    .song-aside {
        position: sticky;
        top: 5rem;
    }
}

/* --- Songs we do not have yet -------------------------------------------- */

/* A zero-result search used to be a dead end. These are the candidates from
   LRCLIB, offered as an action rather than an apology. */
.suggest { margin-top: 2.5rem; }

.suggest__title {
    font-family: var(--display);
    font-size: var(--t-lg);
    font-weight: 600;
    margin: .35rem 0 .4rem;
}

.suggest__lede {
    color: var(--fg-muted);
    font-size: var(--t-sm);
    margin: 0 0 1.25rem;
    max-width: 44ch;
}

.row--suggest {
    /* A form, not a link, so it needs the row layout restated. */
    display: grid;
    grid-template-columns: auto minmax(0, 1fr) auto;
    align-items: center;
    gap: 1rem;
    width: 100%;
    text-align: left;
}

.suggest__album {
    display: block;
    font-size: var(--t-xs);
    color: var(--fg-dim);
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}

.suggest__meta {
    display: flex; align-items: center; gap: .6rem;
    flex-wrap: wrap; justify-content: flex-end;
}

.btn--sm { padding: .4rem .9rem; font-size: var(--t-sm); }

.notice--warn {
    border-left-color: var(--accent);
}

@media (max-width: 34rem) {
    .row--suggest { grid-template-columns: auto minmax(0, 1fr); }
    .suggest__meta { grid-column: 1 / -1; justify-content: flex-start; }
}

/* Suggestion covers are square album art, not 16:9 video stills, and they
   arrive at 600px. Without a size they rendered at full width and pushed the
   rest of the row off the page. */
.row--suggest .art {
    width: 3.5rem;
    aspect-ratio: 1;
    flex: none;
}

.row--suggest .art img {
    width: 100%;
    height: 100%;
    object-fit: cover;
}

/* --- Missing covers ------------------------------------------------------ */

/* Not every song has artwork: LRCLIB carries none, Apple does not list
   everything, and the older catalogue depends on a matched YouTube video. An
   empty box reads as a broken image, so the gap gets the site's own mark and
   looks like a decision. */
.art--empty {
    display: grid;
    place-items: center;
    background:
        radial-gradient(120% 120% at 30% 20%, rgba(255, 101, 16, .16), transparent 62%),
        var(--surface-2);
    border: 1px solid var(--border-soft);
    color: var(--brand-bright);
}

.art__placeholder {
    width: 46%;
    height: auto;
    max-width: 3rem;
    opacity: .85;
}

/* On a wide 16:9 tile the mark would swim, so it is held to the short edge. */
.card__art.art--empty .art__placeholder,
.row .art--empty .art__placeholder { width: 34%; }

.row--suggest .art--empty .art__placeholder { width: 58%; }

/* Apple lists songs LRCLIB has no words for. The row is still offered, since
   the exact-name lookup often finds what the free-text search missed, but it
   should not look as certain as one we know we can read. */
.badge--soft {
    background: transparent;
    border-color: var(--border);
    color: var(--fg-dim);
}

/* "Show more" for the sister-site list. A link rather than a script: the whole
   list is already gathered and cached, so this is a slice, not a lookup. */
.suggest__more {
    display: flex; align-items: center; gap: .9rem;
    margin: 1.5rem 0 0;
}

.suggest__count {
    font-size: var(--t-sm);
    color: var(--fg-dim);
    font-variant-numeric: tabular-nums;
}

/* --- A song nobody has read yet ------------------------------------------ */

/* Rendered server-side rather than fetched, so it is correct without
   JavaScript and for readers who never click. Asking records a request; the
   writing happens out of band under the daily spend cap. */
.unread {
    border: 1px solid var(--border);
    border-left: 3px solid var(--brand);
    border-radius: var(--r-md);
    background: var(--surface);
    padding: clamp(1.25rem, 3vw, 1.9rem);
    max-width: var(--measure);
}

.unread__state {
    margin: 0 0 1.1rem;
    color: var(--fg-muted);
    line-height: 1.6;
}

.unread__state strong { color: var(--fg); }
.unread__state[data-state="queued"] { margin-bottom: 0; }

.unread__note {
    margin: 1rem 0 0;
    font-size: var(--t-sm);
    color: var(--fg-dim);
}

/* An inline link inside body copy.
   The global reset strips colour and underline from every anchor, which is
   right for cards and rows where the whole tile is the target. Inside a
   sentence it left the link indistinguishable from the text around it, so
   these two carried no affordance at all. */
.link-quiet {
    color: var(--brand-bright);
    text-decoration: underline;
    text-underline-offset: 2px;
    text-decoration-thickness: 1px;
    transition: color var(--fast) var(--ease);
}

.link-quiet:hover { color: var(--fg); }
