/* Apollo Save Decrypters & Fixers — layout on top of style.css's tokens. */

.tagline {
    margin: 6px 0 0;
    color: var(--ink-dim);
    max-width: 62ch;
}

.tools-main {
    max-width: 1100px;
    margin: 0 auto;
    padding: 20px 16px 60px;
}

.filters {
    display: flex;
    flex-wrap: wrap;
    gap: 10px;
    align-items: center;
    margin-bottom: 18px;
}

#search {
    flex: 1 1 260px;
    min-width: 0;
    padding: 9px 12px;
    font: inherit;
    color: var(--ink);
    background: var(--panel);
    border: 1px solid var(--line);
    border-radius: var(--radius);
}

.chips { display: flex; flex-wrap: wrap; gap: 6px; }

.chip {
    padding: 7px 12px;
    font: inherit;
    font-size: 13px;
    color: var(--ink-dim);
    background: var(--panel);
    border: 1px solid var(--line);
    border-radius: 999px;
    cursor: pointer;
}
.chip:hover { color: var(--ink); }
.chip.on {
    color: var(--accent-ink);
    background: var(--accent);
    border-color: var(--accent);
}

.count { margin: 0 0 0 auto; color: var(--ink-dim); font-size: 13px; }

/* #grid holds one <section> per console; the cards themselves are the nested
   .cards grid. Keeping the card grid inside each section is what lets a
   platform heading span its own block rather than floating over everything. */
.grid { display: flex; flex-direction: column; gap: 26px; }

.platform-head {
    display: flex;
    align-items: baseline;
    gap: 8px;
    margin: 0 0 10px;
    font-size: 13px;
    font-weight: 600;
    letter-spacing: .06em;
    text-transform: uppercase;
    color: var(--ink-dim);
    padding-bottom: 6px;
    border-bottom: 1px solid var(--line);
}
.platform-count {
    font-size: 11px;
    font-weight: 400;
    letter-spacing: 0;
    text-transform: none;
    color: var(--ink-dim);
    opacity: .75;
}

.cards {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
    gap: 10px;
}

.card {
    display: grid;
    grid-template-columns: auto 1fr;
    grid-template-areas:
        "icon name"
        "icon meta";
    align-content: center;
    column-gap: 12px;
    row-gap: 4px;
    padding: 14px;
    text-align: left;
    font: inherit;
    color: var(--ink);
    background: var(--panel);
    border: 1px solid var(--line);
    border-radius: var(--radius);
    cursor: pointer;
}
.card:hover { border-color: var(--accent); }
/* Redundant now that cards sit under a platform heading — kept in the markup
   for the dialog's aria description and for anyone reading the DOM. */
.card-plat { display: none; }

.card-plat-unused {
    grid-area: plat;
    align-self: flex-start;
    font-size: 11px;
    letter-spacing: .04em;
    text-transform: uppercase;
    color: var(--ink-dim);
}
.card-name { grid-area: name; font-weight: 600; line-height: 1.3; }
.card-meta { grid-area: meta; font-size: 12px; color: var(--ink-dim); }

/* Icons are optional — coverage is partial and tools.js removes the <img>
   when nothing matches. The grid column collapses when it does, so a card
   without art is a card without art rather than a card with a hole in it.

   Sized by HEIGHT with the width left to follow, because the consoles do not
   agree on a shape: PS3 art is 320x176, PS4 is 512x512, PS Vita is 250x320
   (portrait), and PSP is both 144x80 and 80x80 depending on the title. Any
   fixed box would crop or letterbox most of them. A common height instead
   keeps the row of cards visually level while every icon keeps its own
   proportions; max-width stops an unusually wide one from crowding the text.
   object-fit is contain rather than cover so nothing is ever cropped. */
.card-icon {
    grid-area: icon;
    height: 72px;
    width: auto;
    max-width: 132px;
    border-radius: 6px;
    object-fit: contain;
}

/* A group whose patches carry different game names — the LEGO checksum covers
   four titles — says so on the card, so the one name it shows does not read as
   the only game it handles. */
.card-more { color: var(--ink-dim); font-weight: 400; font-size: 12px; }

/* A patch that holds several tools asks which one first. */
.variants { margin: 0 0 12px; }
.variants .variant { font-size: 13px; }

/* ---- a {TAG} choice the patch leaves to the user ---- */

.options { display: grid; gap: 10px; margin: 0 0 12px; }
.option-head {
    display: flex;
    align-items: baseline;
    gap: 8px;
    margin: 0 0 6px;
    font-size: 13px;
}
.option-label { font-weight: 600; }
/* The raw {TAG}. Useful for matching what you see against the .savepatch, and
   one of them is 34 characters long, so it is capped rather than trusted. */
.option-tag {
    font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
    font-size: 11px;
    color: var(--ink-dim);
    max-width: 14em;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.option-pick {
    font: inherit;
    font-size: 13px;
    padding: 8px 10px;
    width: 100%;
    color: var(--ink);
    background: var(--panel);
    border: 1px solid var(--line);
    border-radius: 8px;
}
/* Until it is answered this is the one thing standing between the user and
   the buttons, so it gets the accent outline rather than sitting quiet. */
.options.unset .option-pick { border-color: var(--accent); }
.option-why { margin: 6px 0 0; font-size: 12px; color: var(--ink-dim); }

/* ---- the files a tool needs ---- */

.slots { list-style: none; margin: 12px 0 0; padding: 0; display: grid; gap: 8px; }
.slot {
    display: flex;
    align-items: baseline;
    gap: 10px;
    padding: 9px 12px;
    border: 1px solid var(--line);
    border-radius: 8px;
    background: var(--panel-2);
    font-size: 13px;
}
.slot.filled { border-color: var(--good); }
.slot-target {
    flex: none;
    min-width: 8.5em;
    font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
    font-size: 12px;
    color: var(--ink-dim);
    overflow-wrap: anywhere;
}
.slot-file { flex: 1; overflow-wrap: anywhere; }
.slot-pick { flex: none; }

/* ---- what a multi-file run produced ---- */

.outputs { display: grid; gap: 8px; margin-top: 12px; }
.output {
    display: flex;
    align-items: baseline;
    gap: 10px;
    padding: 9px 12px;
    border: 1px solid var(--line);
    border-radius: 8px;
    font-size: 13px;
}
.output-name {
    flex: none;
    min-width: 8.5em;
    font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
    font-size: 12px;
    overflow-wrap: anywhere;
}
.output-note { flex: 1; color: var(--ink-dim); }
.output.same { opacity: .62; }

.empty { color: var(--ink-dim); }
.linkish {
    font: inherit;
    color: var(--accent);
    background: none;
    border: 0;
    padding: 0;
    cursor: pointer;
    text-decoration: underline;
}

/* The page's one footer carries both the "what does verified mean" note and
   the credits. The note is the part people read, so it keeps the body size
   while the credits below it stay at .credits' smaller 12px. */
.credits .foot-lede {
    color: var(--ink-dim);
    font-size: 13px;
    margin-bottom: 12px;
    padding-bottom: 12px;
    border-bottom: 1px solid var(--line);
}

/* ---- the per-game dialog ---- */

.tool-dialog {
    width: min(560px, calc(100vw - 32px));
    padding: 22px;
    color: var(--ink);
    background: var(--panel);
    border: 1px solid var(--line);
    border-radius: var(--radius);
}
.tool-dialog::backdrop { background: rgba(0, 0, 0, .45); }
.tool-dialog h2 { margin: 0 8px 2px 0; font-size: 19px; }
.tool-sub { margin: 0; color: var(--ink-dim); font-size: 13px; }
/* The title IDs are links to the patch each one came from. Underlined only on
   hover: a dialog subtitle that is mostly IDs turns into a wall of rules
   otherwise. */
.tool-also { margin: 4px 0 0; color: var(--ink-dim); font-size: 12px; }
.tool-sub a { color: var(--accent); text-decoration: none; }
.tool-sub a:hover { text-decoration: underline; }

.tool-head {
    display: flex;
    align-items: center;
    gap: 14px;
    margin-bottom: 16px;
}
/* Same height-driven sizing as the cards, for the same reason: the consoles
   disagree about icon shape. */
.tool-icon {
    height: 64px;
    width: auto;
    max-width: 118px;
    border-radius: 8px;
    object-fit: contain;
    flex: none;
}

.busy {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 20px 16px;
    color: var(--ink-dim);
    background: var(--panel-2);
    border: 1px solid var(--line);
    border-radius: var(--radius);
}
.spinner {
    flex: none;
    width: 18px;
    height: 18px;
    border: 2px solid var(--line);
    border-top-color: var(--accent);
    border-radius: 50%;
    animation: spin .7s linear infinite;
}
@keyframes spin { to { transform: rotate(360deg); } }

/* Someone who has asked for less motion still needs to know it is working, so
   the ring stays and simply stops turning. */
@media (prefers-reduced-motion: reduce) {
    .spinner { animation: none; }
}

.tool-close-form { float: right; margin: -6px -6px 0 0; }
.tool-close {
    font: inherit;
    font-size: 22px;
    line-height: 1;
    color: var(--ink-dim);
    background: none;
    border: 0;
    cursor: pointer;
}
.tool-close:hover { color: var(--ink); }

.drop {
    padding: 26px 16px;
    text-align: center;
    background: var(--panel-2);
    border: 2px dashed var(--line);
    border-radius: var(--radius);
    cursor: pointer;
}
.drop.over, .drop:hover { border-color: var(--accent); }
.drop:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.drop-main { margin: 0; font-weight: 600; }
.drop-sub { margin: 4px 0 0; color: var(--ink-dim); font-size: 13px; }

.loaded {
    padding: 12px 14px;
    background: var(--panel-2);
    border: 1px solid var(--line);
    border-radius: var(--radius);
}
.loaded p { margin: 0 0 4px; word-break: break-all; }
.dim { color: var(--ink-dim); font-weight: 400; }

.actions { display: grid; gap: 8px; margin-top: 14px; }

.action {
    display: flex;
    flex-direction: column;
    gap: 2px;
    padding: 12px 14px;
    text-align: left;
    font: inherit;
    color: var(--ink);
    background: var(--panel-2);
    border: 1px solid var(--line);
    border-radius: var(--radius);
    cursor: pointer;
}
.action:hover:not(:disabled) { border-color: var(--accent); }
.action:disabled { opacity: .5; cursor: default; }
.action-label { font-weight: 600; }
.action-hint { font-size: 12px; color: var(--ink-dim); }

.status { margin: 14px 0 0; min-height: 1.4em; font-size: 14px; }
.status.good { color: var(--good); }
.status.bad { color: var(--bad); }

.log-wrap { margin-top: 10px; font-size: 13px; color: var(--ink-dim); }
.log {
    margin: 8px 0 0;
    padding: 10px;
    max-height: 220px;
    overflow: auto;
    font-size: 12px;
    white-space: pre-wrap;
    word-break: break-word;
    background: var(--panel-2);
    border: 1px solid var(--line);
    border-radius: var(--radius);
}

/* ---- PSP savedata ------------------------------------------------------ *
 *
 * The banner sits above the game grid because for a save straight off a
 * Memory Stick the grid cannot help until the console's own layer is off.
 * Styled as a notice rather than a card, so it does not read as one more game.
 */
.psp-banner {
    display: flex;
    flex-wrap: wrap;
    gap: 16px;
    align-items: center;
    justify-content: space-between;
    margin: 0 0 22px;
    padding: 16px 18px;
    background: var(--panel);
    border: 1px solid var(--line);
    border-left: 3px solid var(--accent);
    border-radius: var(--radius);
}
.psp-banner-text { flex: 1 1 320px; min-width: 0; }
.psp-banner h2 { margin: 0 0 4px; font-size: 16px; }
.psp-banner p { margin: 0; font-size: 13px; color: var(--ink-dim); max-width: 62ch; }
.psp-banner code {
    padding: 1px 4px;
    font-size: 12px;
    background: var(--panel-2);
    border: 1px solid var(--line);
    border-radius: 4px;
}
.psp-banner a { color: var(--accent); }

.psp-banner-go {
    display: flex;
    flex-direction: column;
    gap: 2px;
    flex: none;
    padding: 10px 16px;
    text-align: left;
    font: inherit;
    color: var(--accent-ink);
    background: var(--accent);
    border: 1px solid var(--accent);
    border-radius: var(--radius);
    cursor: pointer;
}
.psp-banner-go:hover { filter: brightness(1.08); }
.psp-banner-go .action-hint { color: var(--accent-ink); opacity: .82; }

/* What PARAM.SFO turned out to say. A definition list because each row is a
 * fact about the save, not a control -- except the file picker, which has to
 * live next to the list it is picking from. */
.psp-info { margin-top: 12px; }
.psp-facts {
    display: grid;
    grid-template-columns: auto 1fr;
    gap: 6px 14px;
    margin: 0;
    padding: 12px 14px;
    font-size: 13px;
    background: var(--panel-2);
    border: 1px solid var(--line);
    border-radius: var(--radius);
}
.psp-facts dt { color: var(--ink-dim); }
.psp-facts dd { margin: 0; overflow-wrap: anywhere; }
.psp-facts select {
    max-width: 100%;
    padding: 3px 6px;
    font: inherit;
    font-size: 13px;
    color: var(--ink);
    background: var(--panel);
    border: 1px solid var(--line);
    border-radius: 6px;
}
.psp-note {
    margin: 8px 0 0;
    font-size: 12px;
    color: var(--ink-dim);
}
.good-text { color: var(--good); }

.psp-key { margin-top: 12px; }
.psp-key-head {
    display: flex;
    gap: 8px;
    align-items: baseline;
    justify-content: space-between;
    margin: 0 0 6px;
    font-size: 13px;
}
.psp-key-state { color: var(--ink-dim); font-size: 12px; text-align: right; }
.psp-key-inputs { display: flex; flex-wrap: wrap; gap: 10px; align-items: center; }
#psp-key-hex {
    flex: 1 1 22ch;
    min-width: 0;
    padding: 8px 10px;
    font: inherit;
    font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
    font-size: 13px;
    letter-spacing: .04em;
    color: var(--ink);
    background: var(--panel-2);
    border: 1px solid var(--line);
    border-radius: var(--radius);
}
#psp-key-hex:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }
.psp-key-why { margin: 6px 0 0; font-size: 12px; color: var(--ink-dim); }

/* At phone width "Game key" and its state line fight over one row, wrapping
   the label to two lines. Stack them instead. */
@media (max-width: 480px) {
    .psp-key-head { display: block; }
    .psp-key-state { display: block; margin-top: 2px; text-align: left; }
}

/* The console-encryption stage inside a per-game tool dialog. Set apart from
   the patch's own file slots with a rule and a tint, because it is a stage
   wrapped around the run rather than another target the patch asked for. */
.psp-stage {
    margin: 12px 0 0;
    padding: 12px 14px;
    background: var(--panel-2);
    border: 1px solid var(--line);
    border-left: 3px solid var(--accent);
    border-radius: var(--radius);
}
.psp-stage-head {
    display: flex;
    gap: 8px;
    align-items: baseline;
    justify-content: space-between;
    margin: 0;
    font-size: 13px;
}
.psp-stage .slots { margin-top: 8px; }
.psp-stage .slot { background: var(--panel); }
.psp-stage .psp-key { margin-top: 10px; }
.psp-stage code {
    padding: 1px 4px;
    font-size: 12px;
    background: var(--panel);
    border: 1px solid var(--line);
    border-radius: 4px;
}
