/* css/marketplace.css
 *
 * The Marketplace page: the filter panel down the left, the wall of listings
 * on the right, and one listing on its own.
 *
 * WHY THIS IS NOT css/blog.css WITH A FIND AND REPLACE
 *
 * It very nearly is, and that was considered. The two pages solve the same
 * layout problem and the panel's internals here are deliberately the blog's,
 * measurement for measurement, so the site has one idea of what a filter panel
 * looks like rather than two.
 *
 * They are separate files because the two pages diverge where it matters. The
 * blog's results are its own markup; the Marketplace's are the dashboard's
 * script cards, which bring their own grid, their own hover and their own
 * breakpoints. Sharing a stylesheet would mean .blog-list rules that must never
 * touch a .dash-card and .dash-card rules that must never touch a blog post,
 * all in one file, distinguished by nothing but the author's memory.
 *
 * The panel is a sticky <aside> in the content flow, NOT a second fixed
 * sidebar. .sidebar is position:fixed and .main-wrap is offset by its width; a
 * second one of those would have to be fought at every breakpoint. In the flow
 * it stacks above the results when the window narrows, which is what a filter
 * panel should do.
 *
 * The card classes themselves -- .dash-card-author and the avatar in it -- are
 * NOT here. They belong to the card system and live with the rest of it in
 * css/dashboard.css.
 */

.mk-wrap {
    display: grid;
    grid-template-columns: 260px minmax(0, 1fr);
    gap: 24px;
    align-items: start;
}

/* ---- filter panel ------------------------------------------------------- */
.mk-filters {
    position: sticky;
    top: calc(var(--header-height, 60px) + 16px);
    max-height: calc(100vh - var(--header-height, 60px) - 32px);
    overflow-y: auto;
    background: var(--card-bg, #fff);
    border: 1px solid var(--border-color, #e5e7eb);
    border-radius: 8px;
    padding: 16px;
}

.mk-filter-toggle {
    display: none;
}

.mk-filter-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    margin-bottom: 14px;
}

.mk-filter-head h4 {
    margin: 0;
    font-size: .95rem;
}

.mk-clear {
    font-size: .78rem;
    color: var(--text-muted, #6b7280);
}

.mk-filter-group {
    margin-bottom: 18px;
}

.mk-filter-label {
    font-size: .72rem;
    text-transform: uppercase;
    letter-spacing: .06em;
    color: var(--text-muted, #6b7280);
    margin-bottom: 7px;
}

/* "(all selected)" beside the Genre heading. Not uppercased with the heading
   it sits in: it is a sentence about how the boxes below behave, not a label,
   and small caps make a phrase like that harder to read rather than easier. */
.mk-filter-hint {
    text-transform: none;
    letter-spacing: 0;
    font-style: italic;
    opacity: .8;
}

.mk-search,
.mk-select {
    width: 100%;
    padding: 7px 10px;
    border: 1px solid var(--border-color, #ccd2dc);
    border-radius: 5px;
    font: inherit;
    font-size: .88rem;
    box-sizing: border-box;
    background: #fff;
}

.mk-facet {
    list-style: none;
    margin: 0;
    padding: 0;
}

.mk-facet li {
    margin-bottom: 3px;
}

.mk-facet label {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 4px 6px;
    border-radius: 4px;
    cursor: pointer;
    font-size: .87rem;
}

.mk-facet label:hover {
    background: var(--hover-bg, #f4f6f9);
}

.mk-facet input {
    margin: 0;
    flex: none;
}

.mk-facet-name {
    flex: 1 1 auto;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* The hand that marks a request on the cards, in front of the filter that
   finds them, so the control and its results are recognisably the same
   subject. Muted: it is a label's ornament, not one of the coloured state
   marks -- see .mk-req-mark. */
.mk-facet-icon {
    margin-right: 5px;
    color: var(--text-muted);
}

.mk-facet-count {
    flex: none;
    font-size: .75rem;
    color: var(--text-muted, #6b7280);
    background: var(--hover-bg, #eef1f5);
    border-radius: 10px;
    padding: 1px 7px;
}

.mk-facet-any {
    font-style: italic;
    color: var(--text-muted, #6b7280);
}

/* The genre list grows as the site does, so cap it rather than pushing the
   length bands off the bottom of the panel. */
.mk-facet-scroll {
    max-height: 260px;
    overflow-y: auto;
}

/* ---- the change-confirmed toast ----------------------------------------- */

/* Across the top of the screen for a second when a screenplay goes into or
   comes out of the Marketplace -- see mkToast() in js/marketplace.js, which
   carries the padding and the timing. What is here is only the type, which the
   Swal options cannot set.

   Bigger than the site's other toast, on purpose: that one is a background
   notification and this is the whole of the answer to a click that was just
   made, so it is meant to be caught out of the corner of the eye rather than
   read carefully. */
.mkToastPopup .swal2-title {
    font-size: 19px;
    line-height: 1.2;
    padding: 0;
    margin: 0;
    color: var(--text-dark);
}

.mkToastPopup .swal2-icon {
    font-size: 22px;
}

/* ---- the Staff view ----------------------------------------------------- */

/* Dashed rather than solid, matching .blog-staff-only: the site has one way of
   saying "this box is not what everybody sees", and two would be one too many. */
.mk-staff-only {
    border: 1px dashed var(--border-color, #d6d0bf);
    border-radius: 6px;
    padding: 10px 12px;
    background: rgba(0, 0, 0, .015);
}

.mk-staff-only .mk-filter-label {
    margin-bottom: 5px;
}

/* Said again beside the result count, because the number means something
   different with the box ticked and the panel may be scrolled away. */
.mk-scope-note {
    font-size: .8rem;
    font-style: italic;
    color: var(--text-muted, #8094ae);
}

/* Which of these the author actually offered. Only ever drawn in the Staff
   view -- on the ordinary wall every card is listed and a badge on all of them
   would say nothing. */
.mk-badge {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    padding: 2px 9px;
    border-radius: 11px;
    font-size: .7rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: .04em;
    white-space: nowrap;
    border: 1px solid transparent;
}

.mk-badge-on {
    background: #dff5ea;
    border-color: #9fd9bd;
    color: #17694a;
}

/* Muted, not alarming. An unlisted screenplay is the ordinary state of a
   script and not a fault -- most of them will never be offered, and a red
   badge down a wall of ninety-seven would read as ninety-seven problems. */
.mk-badge-off {
    background: var(--hover-bg, #eef1f5);
    border-color: var(--border-color, #d8dde5);
    color: var(--text-muted, #8094ae);
}

/* Switched on by its author, but their membership no longer covers the
   Marketplace, so no member can see it. Amber rather than green or grey: it is
   neither of the ordinary states, and it is the one worth a second look --
   somebody who meant to be selling here and does not know they are not.
   Wider than the other two, so a badged card reserves room for this one. */
.mk-badge-lapsed {
    background: #fdf3d8;
    border-color: #edd08a;
    color: #8a6416;
}

/* ---- the wall ----------------------------------------------------------- */
.mk-list-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px 20px;
    /* The pager up here can be eleven buttons wide, so the row has to be
       allowed to break rather than squeeze the count into two words a line. */
    flex-wrap: wrap;
    /* Indented to the cards below it.
     *
     * The wall of cards is .dash-grid or .dash-rows, and both carry padding:10px
     * -- so the first card starts 10px in from the panel's edge and the last one
     * ends 10px short of it. This row is a sibling of that wall with no padding
     * of its own, so without this the count hangs off the left of the cards and
     * the pager and shape switch hang off their right.
     *
     * Both ends, not just the left: the overhang was symmetrical and so is the
     * fix. Hardcoded rather than read from a variable because the 10px belongs
     * to those two dashboard classes and there is no token for it -- if that
     * padding ever changes, this is the line that has to change with it. */
    padding: 0 10px;
    margin-bottom: 6px;
}

.mk-result-count {
    font-size: 18px;
    color: var(--text-muted, #6b7280);
}

/* The pager and the shape switch as one block on the right, so the pager sits
   against the buttons instead of drifting into the middle of the row. */
.mk-list-tools {
    display: flex;
    align-items: center;
    gap: 14px;
    margin-left: auto;
}

/* The foot's pager stands off the last row of cards; this one is already inside
   a row that has its own spacing, and the 22px would push the switch beside it
   out of line with the count. */
.mk-list-tools .mk-pager {
    margin-top: 0;
    /* Not centred like the one at the foot: this pager is the right-hand end of
       a row, and centring it would leave a gap between it and the switch that
       grows and shrinks with the number of pages. */
    justify-content: flex-end;
}

/* Dimmed rather than emptied while a new page is fetched.
   Blanking the panel makes every filter click three events to watch -- results
   go, pause, results come back -- and the blank is the worst of the three,
   because the page collapses and then jumps as it refills. See listBusy() in
   js/dashboard.js, which makes the same argument at length about the lists it
   owns. Pointer events go with the dimming, so a card cannot be clicked in the
   moment before it is replaced by a different one. */
.mk-list.is-loading {
    opacity: .45;
    pointer-events: none;
    transition: opacity .12s;
}

.mk-empty {
    text-align: center;
    padding: 50px 20px;
    color: var(--text-muted, #6b7280);
}

.mk-empty i {
    font-size: 2rem;
    opacity: .35;
}

.mk-empty p {
    margin: 0;
}

/* Windowed -- at most eleven controls whatever the page count. See
   listPagerBlock() in includes/listlayout.php, which decides which numbers
   these are; what is here is only how they look. flex-wrap survives from the
   old unbounded pager and is kept as a floor rather than a plan: eleven small
   buttons still need somewhere to go on a narrow phone. */
.mk-pager {
    display: flex;
    gap: 6px;
    justify-content: center;
    align-items: center;
    margin-top: 22px;
    flex-wrap: wrap;
}

.mk-page {
    min-width: 34px;
    padding: 6px 10px;
    text-align: center;
    border: 1px solid var(--border-color, #e5e7eb);
    border-radius: 5px;
    text-decoration: none;
    color: inherit;
    font-size: .85rem;
}

.mk-page:hover {
    background: var(--hover-bg, #f4f6f9);
    cursor: pointer;
}

.mk-page.current {
    background: var(--primary, #e85347);
    border-color: var(--primary, #e85347);
    color: #fff;
}

/* Prev and Next. Wider than a number because they carry a word beside the
   chevron, and they keep their place at both ends of the row on every page --
   greyed where there is nowhere to go, rather than removed, so the numbers
   between them do not shift sideways on the first and last page. */
.mk-page-nav {
    display: inline-flex;
    align-items: center;
    gap: 6px;
}

.mk-page-nav.is-disabled {
    opacity: .4;
    cursor: default;
    pointer-events: none;
}

/* The word goes at the narrowest widths and the chevron stands alone. Both
   arrows keep an accessible name either way -- see the aria-labels in
   listPagerBlock() -- so nothing is lost by hiding the text. */
@media (max-width: 480px) {
    .mk-page-nav span {
        display: none;
    }
}

/* Not a button: nothing to click, nowhere to go. Sized to a number so the row
   does not visibly tighten where a run has been left out. */
.mk-gap {
    min-width: 20px;
    text-align: center;
    color: var(--text-muted, #8094ae);
    font-size: .85rem;
    user-select: none;
}

/* ---- one listing -------------------------------------------------------- */
.mk-listing {
    max-width: 1000px;
}

.mk-listing .back-btn {
    margin-bottom: 10px;
}

.mk-listing-grid {
    display: grid;
    grid-template-columns: 260px minmax(0, 1fr);
    gap: 24px;
    align-items: start;
    padding: 20px;
}

.mk-listing-poster img {
    width: 100%;
    border-radius: 8px;
    display: block;
}

/* Stretched to the row, not just to its own contents.
 *
 * The grid is align-items:start, so each column stands only as tall as what is
 * in it -- which is right for the poster and wrong for this. A listing with a
 * short logline and no genres left the action buttons floating well above the
 * bottom of the poster beside them, so where they landed depended on how much
 * the writer had filled in.
 *
 * align-self overrides that for this column alone: the poster keeps its natural
 * height, the body matches whichever of the two is taller, and the auto margin
 * on the actions below has somewhere to push into. When the body is the taller
 * of the two this does nothing at all, which is the case it must not disturb. */
.mk-listing-body {
    display: flex;
    flex-direction: column;
    gap: 14px;
    align-self: stretch;
}

.mk-listing-title {
    margin: 0;
    font-size: 26px;
    font-weight: 700;
    color: var(--text-dark);
    line-height: 1.15;
}

/* Directly under the title and lighter, as it is on a card: an episode name is
   read as the second half of the title, not as another fact about the script.
   Its own margin rather than the body's gap, which would separate the two. */
.mk-listing-episode {
    margin: -10px 0 0;
    font-size: 17px;
    color: var(--text-soft);
}

.mk-listing-logline {
    margin: 0;
    font-size: 20px;
    line-height: 1.3;
    color: var(--color-blue);
}

.mk-listing-section p {
    margin: 4px 0 0;
    color: var(--text-soft);
    line-height: 1.35;
}

.mk-listing-genres {
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
    margin-top: 6px;
}

/* Pinned to the bottom right of the card, wherever the text above it ends.
 *
 * margin-top:auto rather than position:absolute. It puts the buttons in the
 * same place -- the foot of the tallest column, inside the card's padding --
 * without taking them out of the flow, which matters for the two cases absolute
 * positioning gets wrong: a long synopsis would run underneath a pinned button
 * unless the card reserved a strip for it, and at the narrow breakpoint the
 * grid collapses to one column and "the bottom of the card" stops being where
 * this belongs. In the flow it simply follows the content there.
 *
 * flex-end because the pair reads as a card footer: the two buttons stay
 * together and sit against the right edge rather than trailing off the left. */
.mk-listing-actions {
    display: flex;
    flex-wrap: wrap;
    justify-content: flex-end;
    gap: 10px;
    margin-top: auto;
    padding-top: 6px;
}

.mk-author {
    display: flex;
    align-items: center;
    gap: 10px;
    margin-top: 6px;
    width: fit-content;
}

.mk-author-avatar {
    width: 34px;
    height: 34px;
    flex: none;
    border-radius: 50%;
    overflow: hidden;
    background: var(--primary-dim);
    color: var(--primary);
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 13px;
    font-weight: 700;
}

.mk-author-avatar img {
    width: 100%;
    height: 100%;
    object-fit: cover;
}

/* ---- what the AI made of it, under the listing card --------------------- */

/* A block of its own below the card, not inside it -- see renderMarketplaceAi().
   The report markup itself is the summary page's, and its stylesheet is already
   loaded here (both pages are the dashboard), so what is needed is only the
   frame around it. */
.mk-listing-ai {
    max-width: 1000px;
    margin-top: 14px;
    display: flex;
    flex-direction: column;
    gap: 14px;
}

.mk-ai-block {
    background: var(--card-bg, #fff);
    border: 1px solid var(--border-color, #e5e7eb);
    border-radius: 8px;
    padding: 16px 20px;
}

/* The label sits above its report rather than inline with it, as the section
   labels inside the card do. */
.mk-ai-block .script-section-label {
    display: block;
    margin-bottom: 10px;
}

/* The images grid is the Attachments widget's own markup -- .media-image-grid
   and .media-image-item, both already styled in css/dashboard.css -- so it needs
   nothing here beyond room to breathe under the label above it. */
.mk-ai-block .media-image-grid {
    margin-top: 6px;
}

/* ---- the author's switch, on a script's own detail page ----------------- */
.mk-switch-block {
    margin-bottom: 14px;
}

.mk-switch {
    display: flex;
    align-items: center;
    gap: 10px;
    margin-top: 6px;
    cursor: pointer;
    width: fit-content;
}

/* The checkbox itself is taken out of sight rather than out of the document:
   removed with display:none it stops being focusable, and the switch would
   then be unreachable by keyboard. */
.mk-switch input {
    position: absolute;
    opacity: 0;
    width: 1px;
    height: 1px;
}

.mk-switch-track {
    position: relative;
    width: 42px;
    height: 22px;
    flex: none;
    border-radius: 11px;
    background: var(--border, #ccd2dc);
    transition: background .15s;
}

.mk-switch-knob {
    position: absolute;
    top: 3px;
    left: 3px;
    width: 16px;
    height: 16px;
    border-radius: 50%;
    background: #fff;
    transition: transform .15s;
}

.mk-switch input:checked + .mk-switch-track {
    background: var(--success, #1ee0ac);
}

.mk-switch input:checked + .mk-switch-track .mk-switch-knob {
    transform: translateX(20px);
}

/* Visible focus, because the input it belongs to has none of its own now. */
.mk-switch input:focus-visible + .mk-switch-track {
    outline: 2px solid var(--primary, #e85347);
    outline-offset: 2px;
}

.mk-switch-text {
    font-size: 15px;
    color: var(--text-soft);
}

.mk-switch input:disabled + .mk-switch-track {
    opacity: .5;
}

/* A switch that is set but cannot be moved: a lapsed membership, where the
   flag is on and the screenplay is not being shown. The label must not offer
   the pointer that says it can be clicked -- .mk-switch sets one for the
   ordinary case, and a disabled input inside a label the cursor still invites
   you to press is worse than no cursor at all. */
.mk-switch--locked {
    cursor: default;
}

/* The same slider, in a coverage report's action row.
 *
 * .cv-actions is a row of controls -- publish, delete -- and the switch joins
 * them rather than sitting above on a line of its own: all three are the author
 * deciding something about this one report, and separating one of them would
 * read as it being a different kind of thing.
 *
 * margin-top:0 undoes the 6px the switch carries on the script detail page,
 * where it follows a label; here it has a row to line up with. */
.cv-actions .cv-member-switch {
    margin-top: 0;
    margin-right: 4px;
}

.cv-actions .cv-member-switch .mk-switch-text {
    font-size: 14px;
    cursor: help;
}

.mk-switch-warn,
.mk-switch-upsell {
    margin: 8px 0 0;
    font-size: 14px;
    line-height: 1.35;
    color: var(--text-soft);
}

.mk-switch-warn i {
    color: var(--warning, #f4bd0e);
    margin-right: 4px;
}

.mk-switch-upsell i {
    margin-right: 4px;
}

/* ---- narrow ------------------------------------------------------------- */

/* One pager on a phone, not two.
 *
 * The head is already wrapping at this width -- the count on one line, the
 * switch on the next -- and a pager of up to eleven buttons between them takes
 * two more, so a reader would scroll past four lines of furniture before
 * reaching the first card. The pager at the foot is untouched and is the one
 * that matters on a small screen anyway, since getting there means having
 * scrolled through the page already. */
@media (max-width: 640px) {
    .mk-list-tools .mk-pager {
        display: none;
    }
}

@media (max-width: 900px) {

    .mk-wrap,
    .mk-listing-grid {
        grid-template-columns: minmax(0, 1fr);
    }

    /* The poster stops being a column and becomes a header, at a size that
       does not take the whole screen before the logline is reached. */
    .mk-listing-poster {
        max-width: 220px;
    }

    .mk-filter-toggle {
        display: flex;
        align-items: center;
        gap: 8px;
        width: 100%;
        padding: 10px 12px;
        border: 1px solid var(--border-color, #e5e7eb);
        border-radius: 8px;
        background: var(--card-bg, #fff);
        font: inherit;
        cursor: pointer;
    }

    .mk-filter-caret {
        margin-left: auto;
        transition: transform .15s;
    }

    .mk-filter-toggle.open .mk-filter-caret {
        transform: rotate(180deg);
    }

    /* Collapsed by default at this width and opened by the button above. It
       keeps its place in the flow either way -- the whole reason the panel is
       not a fixed sidebar. */
    .mk-filters {
        display: none;
        position: static;
        max-height: none;
    }

    .mk-filters.open {
        display: block;
    }
}

/* What a listing says to somebody who has already asked to read it.

   Not a button: a second request is refused by the unique key and by
   requestScriptAccess.php, so a control here would be one that turns them
   down. It sits in the same row the buttons do and is sized to be read
   alongside them rather than to be pressed. */
.mk-req-state {
    display: inline-flex;
    align-items: center;
    gap: 7px;
    font-size: 15px;
    font-weight: 600;
}

.mk-req-pending {
    color: var(--text-soft);
}

/* Stated, not warned about. A decline is the author exercising a choice the
   feature exists to give them, and a red alert would read as a fault. */
.mk-req-declined {
    color: var(--text-muted);
}

/* The same three states as a mark on the wall's cards -- see
   marketplaceRequestMark(). Sized with the extras beside it rather than with
   the line above: on a card this is one icon among several, and the byline it
   sits on has a fixed floor that a larger glyph would push about.

   Coloured, unlike the line on the listing page, because here there is no
   sentence to read. Three icons in one colour would need learning; a pending
   amber, an approved green and a grey no are read without being learned. */
.mk-req-mark {
    display: inline-flex;
    align-items: center;
    font-size: 15px;
}

.mk-req-mark--pending {
    color: var(--warning);
}

.mk-req-mark--approved {
    color: var(--success);
}

/* Grey, not red, for the same reason .mk-req-declined is: the author said no,
   which is the feature working rather than something going wrong. */
.mk-req-mark--declined {
    color: var(--text-muted);
}

/* An extras icon that carries a number -- the cast count, today.

   Its own span so the number sits against its icon rather than being pushed to
   the far end by the byline row's gap. */
.mk-extra {
    display: inline-flex;
    align-items: center;
    gap: 3px;
}

.mk-extra-count {
    font-size: 14px;
    font-weight: 700;
    color: var(--text-soft);
}
