/* The two families the site writes with, served from our own domain. The
   Google Fonts stylesheet blocked the render for 830 ms on mobile before a
   single word appeared; see samples/static/samples/fonts/README.md.

   Outfit is a variable font: one file covers 400 to 600, which is why a single
   rule declares the whole range rather than three rules naming one weight each.
   `swap` is what the Google stylesheet asked for and the reason the text shows
   at once, in a fallback, instead of waiting behind the download. */
@font-face {
    font-family: 'Outfit';
    font-style: normal;
    font-weight: 400 600;
    font-display: swap;
    src: url("../fonts/outfit-latin.98ccc2b7f189.woff2") format('woff2');
    unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

@font-face {
    font-family: 'Outfit';
    font-style: normal;
    font-weight: 400 600;
    font-display: swap;
    src: url("../fonts/outfit-latin-ext.e2b64ddcb351.woff2") format('woff2');
    unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

@font-face {
    font-family: 'Luckiest Guy';
    font-style: normal;
    font-weight: 400;
    font-display: swap;
    src: url("../fonts/luckiest-guy-latin.f5b9f8046bb4.woff2") format('woff2');
    unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

@font-face {
    font-family: 'Luckiest Guy';
    font-style: normal;
    font-weight: 400;
    font-display: swap;
    src: url("../fonts/luckiest-guy-latin-ext.68892b67b2f1.woff2") format('woff2');
    unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

:root {
    --background: #0f1720;
    --surface: #1a2633;
    /* The lime of SiteAppearance.ACCENT_COLORS, for a render without the
       context processor. A test keeps the two equal. */
    --primary: #7FD400;
    --on-primary: #1a2633;
    --text-primary: #FFFFFF;
    --text-secondary: #DDDDDD;
    --border: #2C2C2C;
    --success: #4CAF50;
    --warning: #FF9800;
    --error: #F44336;
    /* The hardware look of the application buttons (LaSoundboard#8): a dark
       recessed face, a light frame, a grey pictogram that lights up in the
       accent. The page player borrows it so the site and the app speak the
       same visual language. */
    --control-face: #121a23;
    --control-frame: #c9cfd6;
    --control-frame-lit: #dfe3e8;
    --control-rim: #59636e;
    --control-icon: #7f8a95;
    --control-track: #2b3846;
    --control-tray: #0b1118;
}

/* The one rule for links, site-wide. Without it the browser's own blue shows,
   unreadable on the dark background, and pages took to restating it each for
   itself: six copies, and two pages that forgot. :where() keeps the specificity
   at zero, so a component styling its own links (footer, buttons, cards) still
   wins. A page wanting another colour sets --link; it never copies the rule. */
:where(a) {
    color: var(--link, var(--primary));
    text-decoration: none;
}

:where(a):hover {
    text-decoration: underline;
}

body {
    font-family: 'Outfit', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
    line-height: 1.6;
    margin: 0;
    padding: 0;
    background: var(--background);
    color: var(--text-primary);
    min-height: 100vh;
}

.site-header {
    background: var(--surface);
    padding: 1rem;
    border-bottom: 1px solid var(--border);
    position: sticky;
    top: 0;
    z-index: 100;
}

.header-content {
    max-width: 800px;
    margin: 0 auto;
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 1rem;
}

.header-logo {
    height: 4rem;
    width: auto;
    margin-bottom: 1em;
}

@media (min-width: 768px) {
    .header-logo {
        height: 5.5rem;
    }
}

.site-title {
    color: var(--primary);
    margin: 0;
    font-size: 2rem;
    font-weight: 600;
    font-family: 'Luckiest Guy', cursive;
    text-shadow: 1px -1px 1px rgba(255, 255, 255, 1);
}

@media (min-width: 768px) {
    .site-title {
        font-size: 3rem;
    }
}

.sample-container {
    max-width: 800px;
    margin: 0 auto;
    padding: 1rem;
}

.sample-header {
    background: var(--surface);
    border-radius: 12px;
    padding: 1.5rem;
    margin-bottom: 1.5rem;
    box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
}

.sample-content {
    display: flex;
    flex-direction: column;
    gap: 2rem;
}

.sample-title {
    text-align: center;
}

.sample-title h1 {
    margin: 0;
    font-size: 2rem;
    color: var(--text-primary);
}

/* The line the sample says, under its name. A blockquote and not a paragraph:
   it is a quotation, and the markup is the only thing that says so to anything
   that is not looking at the page. */
.sample-quote {
    margin: 0.75rem auto 0;
    max-width: 40rem;
    padding-left: 1rem;
    border-left: 3px solid var(--border);
    color: var(--text-secondary);
    font-size: 1.05rem;
    font-style: italic;
    text-align: left;
}

.sample-columns {
    display: flex;
    flex-direction: column;
    gap: 2rem;
}

/* Flex at every width: the description is written once, as the last child, and
   `order` brings it back to the top above 768px. Two copies toggled by display
   were both read by a crawler, which found every description twice. The gap
   reproduces the one .main-content gave it while it was nested there. */
.right-column {
    display: flex;
    flex-direction: column;
    gap: 2rem;
}

@media (min-width: 768px) {
    .sample-columns {
        flex-direction: row;
        gap: 0;
    }

    .left-column {
        flex: 0 0 300px;
        padding: 2rem;
    }

    .right-column {
        flex: 1;
        padding-right: 2rem;
    }

    .right-column .sample-metadata {
        order: -1;
    }

    .main-content {
        display: flex;
        flex-direction: column;
        gap: 2rem;
    }
}

.sample-image {
    width: 100%;
    height: auto;
    border-radius: 8px;
}

.audio-player {
    width: 100%;
}

.audio-player audio {
    width: 100%;
}

.store-buttons {
    display: flex;
    gap: 1rem;
    justify-content: center;
    align-items: center;
}

.download-text {
    text-align: center;
    color: var(--text-secondary);
    margin: 0;
}

.mobile-only {
    display: block;
}

.desktop-only {
    display: none;
}

@media (min-width: 768px) {
    .mobile-only {
        display: none;
    }

    .desktop-only {
        display: block;
    }
}

.sample-metadata {
    color: var(--text-secondary);
}

.sample-metadata a {
    margin-left: 0.5rem;
}

.sample-metadata a i {
    margin-left: 0.25rem;
    font-size: 0.8em;
}

.sample-image {
    width: 100%;
    max-width: 300px;
    height: auto;
    border-radius: 8px;
    margin: 0 auto;
}

.sample-info h1 {
    margin: 0;
    color: var(--text-primary);
    font-size: 2rem;
    line-height: 1.2;
}

.sample-metadata {
    color: var(--text-secondary);
    margin: 1rem 0;
}

.store-buttons {
    display: flex;
    gap: 1.5rem;
    justify-content: center;
    align-items: center;
}

.store-button img {
    height: 40px;
    width: auto;
}

.download-text {
    margin: 1.5rem 0;
    text-align: center;
    color: var(--text-secondary);
}

.details-link {
    margin-top: 1rem;
}




.audio-player {
    background: var(--surface);
    padding: 1rem;
    border-radius: 12px;
    margin: 1rem 0;
    border: 1px solid var(--border);
}

/* The card once the player has taken over: the recessed tray of the app pads,
   ringed in the accent. On the surface colour of the page around it, the card
   had the very same background and a border the eye could barely find. The
   class comes from the script, so a page left with the native controls keeps
   the plain card those controls are styled for. */
.audio-player.has-player {
    background: var(--control-tray);
    border-color: transparent;
    box-shadow: inset 0 2px 6px #000c,
        0 0 0 1px color-mix(in srgb, var(--primary) 60%, var(--surface)),
        0 0 12px color-mix(in srgb, var(--primary) 22%, transparent);
}

/* The player that replaces the native controls once sample_player.js runs.
   Without the script it stays hidden and the native <audio> plays the sound. */
.sample-player {
    display: flex;
    align-items: center;
    gap: 1.25rem;
}

/* An author display rule outranks the hidden attribute: without this one the
   player would show, dead, on a page where the script never ran. */
.sample-player[hidden] {
    display: none;
}

.sample-player-button {
    flex: none;
    width: 56px;
    height: 56px;
    margin: 4px;
    padding: 0;
    border: 0;
    /* The square controller buttons of the app round their corners 7px at
       40px; the same proportion at 56px */
    border-radius: 10px;
    display: grid;
    place-items: center;
    cursor: pointer;
    font-size: 22px;
    color: var(--control-icon);
    background: var(--control-face);
    box-shadow: 0 0 0 2px var(--control-frame), 0 0 0 3px var(--control-rim),
        inset 0 3px 6px #000a, inset 0 -1px 0 #ffffff14;
    transition: color .25s ease-out, box-shadow .25s ease-out, transform .06s;
    -webkit-tap-highlight-color: transparent;
}

.sample-player-button i {
    transition: filter .25s ease-out;
}

/* Centred by its box, a play triangle still looks pushed left: its weight sits
   on the flat side, a third of the way across. Moved by a sixth of its width,
   0.75em in Font Awesome, the eye finds it in the middle. The pause bars are
   symmetric and stay where the grid puts them. */
.sample-player-button .fa-play {
    transform: translateX(.12em);
}

.sample-player-button:active {
    transform: translateY(1px);
    transition-duration: .04s;
}

.sample-player-button:focus-visible {
    outline: 2px solid var(--text-primary);
    outline-offset: 5px;
}

/* Lit from the press until the sound stops, as the pads are in the app. */
.sample-player-button.is-lit {
    color: var(--primary);
    box-shadow: 0 0 0 2px color-mix(in srgb, var(--primary) 45%, var(--control-frame-lit)),
        0 0 0 3px var(--control-rim),
        0 0 14px 1px color-mix(in srgb, var(--primary) 45%, transparent),
        inset 0 3px 6px #000a,
        inset 0 0 10px color-mix(in srgb, var(--primary) 25%, transparent);
}

.sample-player-button.is-lit i {
    filter: drop-shadow(0 0 4px var(--primary)) drop-shadow(0 0 1px #fff8);
}

.sample-player-body {
    flex: 1;
    min-width: 0;
}

.sample-player-head {
    display: flex;
    justify-content: space-between;
    align-items: baseline;
    gap: .5rem;
}

/* The name of the sample: one line, cut with an ellipsis, so that a long
   name leaves the clock in its place on the right. */
.sample-player-label {
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    font-weight: 500;
    color: var(--text-primary);
}

.sample-player-time {
    font-size: .85rem;
    color: var(--control-icon);
    font-variant-numeric: tabular-nums;
}

.sample-player-track {
    position: relative;
    height: 5px;
    margin-top: .75rem;
    border-radius: 3px;
    background: var(--control-track);
    cursor: pointer;
}

/* A track five pixels high is a hard target for a finger: the clickable
   area reaches eight pixels above and below it. */
.sample-player-track::before {
    content: "";
    position: absolute;
    inset: -8px 0;
}

.sample-player-track:focus-visible {
    outline: 2px solid var(--text-primary);
    outline-offset: 6px;
}

.sample-player-fill {
    position: absolute;
    inset: 0 auto 0 0;
    width: 0;
    border-radius: 3px;
    background: var(--primary);
    box-shadow: 0 0 6px color-mix(in srgb, var(--primary) 70%, transparent);
    pointer-events: none;
}

@media (prefers-reduced-motion: reduce) {
    .sample-player-button,
    .sample-player-button i {
        transition: none;
    }
}

audio {
    width: 100%;
    outline: none;
    border-radius: 0;
    background: var(--surface);
}

audio::-webkit-media-controls-panel {
    background: var(--surface) !important;
    border-radius: 0 !important;
}

audio::-webkit-media-controls-enclosure {
    border-radius: 0 !important;
    background: var(--surface) !important;
}

audio::-webkit-media-controls,
audio::-webkit-media-controls-panel,
audio::-webkit-media-controls-timeline-container,
audio::-webkit-media-controls-timeline {
    background: var(--surface) !important;
    border-radius: 0 !important;
}

audio::-webkit-media-controls-current-time-display {
    color: white !important;
}

audio::-webkit-media-controls-time-remaining-display {
    color: white !important;
}

audio::-webkit-media-controls-play-button,
audio::-webkit-media-controls-mute-button {
    filter: invert(100%);
}

audio::-webkit-media-controls-volume-slider {
    writing-mode: bt-lr !important;
    -webkit-appearance: slider-vertical !important;
    width: 2px !important;
    height: 40px !important;
    padding: 0 !important;
    margin: 0 10px !important;
    background: white !important;
}

audio::-webkit-media-controls-volume-slider::-webkit-slider-thumb {
    -webkit-appearance: none !important;
    width: 8px !important;
    height: 8px !important;
    border-radius: 50% !important;
    background: white !important;
}

.audio-player {
    padding: 8px;
    margin-bottom: 1rem;
}

.sample-metadata {
    color: var(--text-secondary);
    font-size: 0.9rem;
    line-height: 1.5;
}


.sample-footer {
    margin-top: 2rem;
    padding-top: 1rem;
    border-top: 1px solid var(--border);
}

.store-buttons {
    display: flex;
    justify-content: center;
    gap: 1rem;
    align-items: center;
    margin: 1.5rem 0;
}

.store-button {
    display: block;
    width: 160px;
    height: 48px;
}

.store-button img {
    width: 100%;
    height: 100%;
    object-fit: contain;
    transition: opacity 0.2s;
}

.store-button img:hover {
    opacity: 0.8;
}

.external-link-icon {
    vertical-align: middle;
    margin-right: 4px;
    color: var(--primary);
}

@media (prefers-color-scheme: dark) {
    audio::-webkit-media-controls-timeline,
    audio::-webkit-media-controls-current-time-display,
    audio::-webkit-media-controls-time-remaining-display {
        color: var(--text-primary);
    }
}