/* ------------------------------------------------------------------
   animated-qr — page-specific styles.

   Lives at the app root, not under /assets/. The deployed vhost aliases
   /assets/ to the main site's docroot, so a file only this app has must
   not sit behind that prefix or nginx answers 404 for it.

   The shared house style (/assets/site.css) already supplies the
   palette, the type, the CRT overlay, .panel, .prompt, ul.list and the
   footer. Everything here is only what that file has no rule for: form
   controls, the preview frame and the embed box. It reuses the same
   idioms deliberately — rgba(127,255,0,0.25) borders at 12px, 0.18s
   ease transitions, chartreuse glow on hover and focus — so the
   controls read as part of the same terminal.
   ------------------------------------------------------------------ */

/* ---- Fixed page, scrolling panel ----

   Same shape as nextslide.hackenshaw.com: the page itself never scrolls, the
   terminal panel does. The shared sheet sizes the body with min-height so it
   can grow; these override that to pin it to the viewport instead. It lives
   here rather than in site.css because that one file is served to every vhost.

   min-height:0 on <main> is the load-bearing line — without it a flex item
   refuses to shrink below its content and the panel just pushes the footer
   off-screen instead of scrolling. */
html,
body {
    height: 100%;
    overflow: hidden;
}

body {
    height: 100vh;
    height: 100dvh; /* survives a phone's collapsing address bar */
}


header,
footer {
    flex-shrink: 0;
}

/* Trimmed to nextslide's proportions. The shared sheet sizes the header for a
   page that can grow; on a page pinned to the viewport that same header eats
   most of a laptop screen and leaves the panel a slot. Same reason nextslide
   runs a smaller avatar and title than the shared sheet does. */
body {
    gap: 2rem;
}

header {
    gap: 0.9rem;
    padding-top: 0;
}

.avatar {
    width: clamp(70px, 11vmin, 100px);
}

h1 {
    font-size: clamp(1.7rem, 6vmin, 2.8rem);
}

footer {
    gap: 1.4rem;
}

footer svg {
    width: 26px;
    height: 26px;
}

main {
    min-height: 0;
}

main .panel {
    max-height: 100%;
}

/* .panel is a flex item of <main>, so its default min-width:auto stops it
   shrinking below its content's min-content width. The embed snippet is one
   long nowrap line, which would otherwise set that floor and push the page
   sideways on a phone. Belongs here rather than in the shared sheet, since it
   is this page's content that needs it. */
main .panel {
    min-width: 0;
}

#controls {
    display: flex;
    flex-direction: column;
    gap: 0.9rem;
    margin-bottom: 1.4rem;
}

.grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(190px, 1fr));
    gap: 0.9rem;
}

.field {
    display: flex;
    flex-direction: column;
    gap: 0.4rem;
    min-width: 0;
}

.field .label {
    color: var(--dim);
    font-size: clamp(0.7rem, 1.8vmin, 0.8rem);
    letter-spacing: 0.06em;
    text-transform: uppercase;
}

.field output {
    color: var(--fg);
    text-transform: none;
    letter-spacing: 0.02em;
}

/* Inputs are terminal fields: the panel showing through a dim rule,
   brightening to full chartreuse when they have focus. */
#controls input[type="text"],
#controls select {
    width: 100%;
    padding: 0.7rem 0.85rem;
    background: transparent;
    color: var(--fg);
    font: inherit;
    font-size: clamp(0.85rem, 2.2vmin, 1rem);
    border: 1px solid rgba(127, 255, 0, 0.25);
    border-radius: 12px;
    transition: border-color 0.18s ease, background 0.18s ease;
}

#controls input[type="text"]:hover,
#controls select:hover {
    border-color: rgba(127, 255, 0, 0.5);
}

#controls input[type="text"]:focus,
#controls select:focus,
#controls input[type="range"]:focus-visible,
#controls input[type="color"]:focus-visible {
    outline: none;
    border-color: var(--fg);
    background: rgba(127, 255, 0, 0.07);
}

#controls select {
    /* The native arrow renders as a light-mode chevron on a dark field. */
    appearance: none;
    background-image: linear-gradient(45deg, transparent 50%, var(--dim) 50%),
        linear-gradient(135deg, var(--dim) 50%, transparent 50%);
    background-position: right 1.05rem center, right 0.75rem center;
    background-size: 6px 6px, 6px 6px;
    background-repeat: no-repeat;
    padding-right: 2rem;
}

#controls select option {
    background: var(--panel);
    color: var(--fg);
}

.url-field input {
    letter-spacing: 0.02em;
}

/* Sliders: a dim track with a chartreuse handle, matched in both engines. */
#controls input[type="range"] {
    appearance: none;
    width: 100%;
    height: 22px;
    background: transparent;
    cursor: ew-resize;
}

#controls input[type="range"]::-webkit-slider-runnable-track {
    height: 2px;
    background: rgba(127, 255, 0, 0.25);
    border-radius: 2px;
}

#controls input[type="range"]::-moz-range-track {
    height: 2px;
    background: rgba(127, 255, 0, 0.25);
    border-radius: 2px;
}

#controls input[type="range"]::-webkit-slider-thumb {
    appearance: none;
    width: 13px;
    height: 13px;
    margin-top: -5.5px;
    border-radius: 3px;
    background: var(--fg);
    transition: filter 0.18s ease, transform 0.18s ease;
}

#controls input[type="range"]::-moz-range-thumb {
    width: 13px;
    height: 13px;
    border: none;
    border-radius: 3px;
    background: var(--fg);
}

#controls input[type="range"]:hover::-webkit-slider-thumb {
    filter: drop-shadow(0 0 8px rgba(127, 255, 0, 0.7));
    transform: scale(1.15);
}

.field.colour input[type="color"] {
    appearance: none;
    width: 100%;
    height: 42px;
    padding: 4px;
    background: transparent;
    border: 1px solid rgba(127, 255, 0, 0.25);
    border-radius: 12px;
    cursor: pointer;
    transition: border-color 0.18s ease;
}

.field.colour input[type="color"]:hover {
    border-color: rgba(127, 255, 0, 0.5);
}

.field.colour input[type="color"]::-webkit-color-swatch-wrapper {
    padding: 0;
}

.field.colour input[type="color"]::-webkit-color-swatch {
    border: none;
    border-radius: 8px;
}

/* The transparent toggle sits under its colour swatch; when it wins, the
   swatch is shown as inert rather than removed, so the layout stays put. */
.field .mini {
    display: flex;
    align-items: center;
    gap: 0.4rem;
    color: var(--dim);
    font-size: clamp(0.68rem, 1.7vmin, 0.78rem);
    letter-spacing: 0.04em;
    cursor: pointer;
    transition: color 0.18s ease;
}

.field .mini:hover {
    color: var(--fg);
}

.field .mini input[type="checkbox"] {
    accent-color: var(--fg);
    margin: 0;
    cursor: pointer;
}

.field.colour input[type="color"]:disabled {
    opacity: 0.35;
    cursor: not-allowed;
}

.advanced summary {
    color: var(--dim);
    font-size: clamp(0.75rem, 2vmin, 0.9rem);
    letter-spacing: 0.06em;
    text-transform: uppercase;
    cursor: pointer;
    padding: 0.3rem 0;
    transition: color 0.18s ease;
    width: fit-content;
}

.advanced summary:hover,
.advanced summary:focus-visible {
    color: var(--fg);
    outline: none;
}

.advanced summary::marker {
    color: var(--dim);
}

.advanced .grid {
    padding-top: 0.9rem;
}

/* ---- Layout: scrolling controls, pinned preview ----

   The code is the point of the page, so it stays on screen while everything
   else scrolls past. It gets its own column rather than floating over the
   content — an overlay pinned to a corner would sit on top of whatever you
   were reading, which is the one thing it must not do.

   The scroller is the controls column, not the panel. Making the panel scroll
   and pinning the code with position:sticky almost works, but a sticky box is
   confined to its containing block: at the end of the scroll it is released
   and slides out of view. Scrolling the column instead means the code is an
   ordinary grid item that never moves, and centring it is one line. */
.panel {
    display: flex;
    overflow: hidden;
}

.layout {
    flex: 1;
    /* Both zeroes are load-bearing. min-width lets it shrink below the
       min-content width of the nowrap embed snippet instead of pushing the
       columns wider than the panel; min-height lets the controls column
       scroll instead of growing past the panel. */
    min-width: 0;
    min-height: 0;
    /* Narrow: code on top, controls scrolling beneath it. */
    display: flex;
    flex-direction: column;
    gap: 0.9rem;
}

.controls-col {
    min-width: 0;
    min-height: 0;
    flex: 1;
    overflow-y: auto;
    overscroll-behavior: contain;
    scrollbar-width: none;
    -ms-overflow-style: none;
}

.controls-col::-webkit-scrollbar {
    width: 0;
    height: 0;
    display: none;
}

.preview-col {
    flex: none;
    min-width: 0;
    /* Narrow: a compact strip — code beside its caption, so it costs as
       little height as possible. */
    display: flex;
    align-items: center;
    gap: 0.9rem;
    padding-bottom: 0.7rem;
    border-bottom: 1px solid rgba(127, 255, 0, 0.15);
}

.preview {
    display: flex;
    justify-content: center;
    flex: none;
}

.preview svg {
    display: block;
    /* Square, so capping the width by viewport height caps the height too —
       max-height would stretch it, since the width is already committed. */
    width: min(130px, 26vh);
    height: auto;
    border-radius: 10px;
}

@media (min-width: 700px) {
    .layout {
        display: grid;
        /* minmax(0,…) not 1fr: a grid track's default minimum is min-content,
           and the nowrap embed snippet would stretch it past the panel. */
        grid-template-columns: minmax(0, 1fr) 270px;
        /* No gap: the gutter is the two columns' own padding, so the rule
           between them lands exactly in the middle of it. */
        gap: 0;
    }

    /* The rule goes on the scrolling column because it is the stretched one,
       so it runs the full height of the panel rather than only as far as the
       code beside it. */
    .controls-col {
        grid-column: 1;
        grid-row: 1;
        padding-right: 1.4rem;
        border-right: 1px solid rgba(127, 255, 0, 0.15);
    }

    .preview-col {
        grid-column: 2;
        grid-row: 1;
        align-self: center;
        display: block;
        padding-left: 1.4rem;
        padding-bottom: 0;
        border-bottom: none;
    }

    .preview svg {
        width: min(100%, 250px, 32vh);
        border-radius: 12px;
    }
}

.note {
    color: var(--dim);
    font-size: clamp(0.72rem, 1.9vmin, 0.85rem);
    line-height: 1.7;
    text-align: center;
    margin-bottom: 1.4rem;
}

/* Beside the code when it is a strip, under it when it is a column. */
.preview-col .note {
    flex: 1;
    min-width: 0;
    margin: 0;
    text-align: left;
}

@media (min-width: 700px) {
    .preview-col .note {
        margin-top: 0.7rem;
        text-align: center;
    }
}

.note code {
    color: var(--fg);
}

.note.warn {
    color: #d8b13a;
}

.prompt.subhead {
    margin-top: 1.6rem;
}

/* ---- Downloads ----
   ul.list already styles the rows; these only cover the disabled state
   for when the export service is not reachable. */
.downloads a.entry {
    cursor: pointer;
}

.downloads li.disabled {
    opacity: 0.4;
}

.downloads li.disabled a.entry {
    pointer-events: none;
}

/* ---- Embed snippet ---- */
.embed {
    display: flex;
    align-items: stretch;
    gap: 0.6rem;
    margin-bottom: 0.9rem;
}

.embed code {
    flex: 1;
    min-width: 0;
    padding: 0.75rem 0.9rem;
    border: 1px solid rgba(127, 255, 0, 0.25);
    border-radius: 12px;
    color: var(--fg);
    font-size: clamp(0.68rem, 1.7vmin, 0.8rem);
    line-height: 1.6;
    overflow-x: auto;
    white-space: nowrap;
}

.embed button {
    flex: none;
    padding: 0 1.1rem;
    background: transparent;
    color: var(--dim);
    font: inherit;
    font-size: clamp(0.75rem, 2vmin, 0.9rem);
    letter-spacing: 0.06em;
    text-transform: uppercase;
    border: 1px solid rgba(127, 255, 0, 0.25);
    border-radius: 12px;
    cursor: pointer;
    transition: color 0.18s ease, border-color 0.18s ease, background 0.18s ease;
}

.embed button:hover,
.embed button:focus-visible {
    color: var(--fg);
    border-color: var(--fg);
    background: rgba(127, 255, 0, 0.07);
    outline: none;
}

@media (max-width: 520px) {
    .embed {
        flex-direction: column;
    }

    .embed button {
        padding: 0.7rem;
    }
}

/* The site turns off its own flicker here; the preview should settle too. */
@media (prefers-reduced-motion: reduce) {
    .preview svg * {
        animation: none !important;
    }
}
