/* SVG Optimizer - the two files and the verdict left, the steps right */

.svo-app {
    position: relative;
    display: flex;
    height: 100%;
    overflow: hidden;
}

.svo-stage {
    flex: 1 1 auto;
    display: flex;
    flex-direction: column;
    min-width: 0;
}

/* --- Preview ------------------------------------------------------- */

.svo-views {
    position: relative;         /* the zoom fabs hang off this */
    flex: 1 1 auto;
    display: flex;
    flex-direction: column;
    min-height: 0;
}

/* Two controls ride on the work surface, both built from the shared stage
   buttons (.gn-studio-fab in common.css) and both joined into ONE
   instrument: the group owns the border, the rounding and the shadow, and
   the buttons inside are surfaces parted by hairlines. What you are
   looking at sits top right, how close you are sits bottom right - the
   same two corners the other studios use for their stage controls. */
.svo-view-fabs,
.svo-zoom-fabs {
    flex-direction: row;
    align-items: stretch;
    gap: 0;
    background-color: #fff;
    border: 1px solid rgba(0, 0, 0, 0.2);
    border-radius: 0.5rem;
    box-shadow: 0 1px 4px rgba(0, 0, 0, 0.25);
    overflow: hidden;
}

/* The house class for a top corner also caps its height, which is there
   so the aspect MENU can scroll inside a stage - this group has no menu,
   so it positions itself and skips a constraint it cannot benefit from */
.svo-view-fabs {
    top: 1rem;
    bottom: auto;
}

/* Clear of the caption strip rather than sitting on it */
.svo-zoom-fabs {
    bottom: 2.25rem;
}

/* The segments give up everything the group now owns */
.svo-view-fabs .gn-studio-fab,
.svo-zoom-fabs .gn-studio-fab {
    /* Smaller than a stage circle on purpose: these are controls you reach
       for now and then, not main actions, and they sit on top of the very
       picture they are there to help you look at */
    width: 36px;
    height: 34px;                          /* the group's own border makes 36 */
    font-size: 0.9rem;
    border: 0;
    border-radius: 0;
    background-color: transparent;
    box-shadow: none;
    cursor: pointer;
}

.svo-view-fabs .gn-studio-fab + .gn-studio-fab,
.svo-zoom-fabs .gn-studio-fab + .gn-studio-fab {
    border-left: 1px solid rgba(0, 0, 0, 0.12);
}

/* The radio inputs are taken out of the flow by Bootstrap, so a label
   follows a label here and the hairline rule above still finds them */
.svo-view-fabs .btn-check + .gn-studio-fab {
    border-left: 1px solid rgba(0, 0, 0, 0.12);
}

.svo-view-fabs .gn-studio-fab:first-of-type {
    border-left: 0;
}

/* Pressing one has to read as a surface lighting up inside the control,
   not as a button of its own growing or shrinking */
.svo-view-fabs .gn-studio-fab:hover,
.svo-zoom-fabs .gn-studio-fab:hover:not(:disabled) {
    background-color: var(--gn-sidebar-hover-bg);
}

.svo-zoom-fabs .gn-studio-fab:active:not(:disabled) {
    transform: none;
    background-color: var(--gn-card-border);
}

/* The chosen view is the one thing here that has a state worth showing */
.svo-view-fabs .btn-check:checked + .gn-studio-fab {
    background-color: var(--gn-accent);
    color: #fff;
}

.svo-view-fabs .btn-check:focus-visible + .gn-studio-fab,
.svo-zoom-fabs .gn-studio-fab:focus-visible {
    outline: 2px solid var(--gn-accent);
    outline-offset: -2px;
}

.svo-zoom-fabs .gn-studio-fab:disabled {
    opacity: 0.35;
}

.svo-zoom-fabs .gn-studio-fab:disabled:hover {
    color: #2b2d42;
    background-color: transparent;
}

/* Wide enough for the largest number it can ever show, so that going from
   100% to 3200% does not widen the control and shove the minus button
   sideways while a finger is on it */
.svo-zoom-level {
    width: auto;
    min-width: 3.75rem;
    padding: 0 0.375rem;
    font-size: 0.75rem;
    font-weight: 600;
    font-variant-numeric: tabular-nums;
}

/* The file name sits in the results bar now - the row that is about this
   particular file anyway */
.svo-file {
    font-size: 0.8rem;
    color: var(--gn-muted);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.svo-results .svo-file {
    max-width: 16rem;
}

.svo-panes {
    flex: 1 1 auto;
    min-height: 0;
    display: flex;
    gap: 1px;
    background-color: var(--gn-card-border);
    /* Sideways drags are ours - the wipe and the pan both run along x -
       while an up-and-down swipe stays with the browser, so the picture
       does not become a hole in the page that refuses to scroll */
    touch-action: pan-y;
}

.svo-pane {
    flex: 1 1 50%;
    min-width: 0;
    display: flex;
    flex-direction: column;
    margin: 0;
    background-color: var(--gn-card-bg);
}

/* A checkerboard, so transparency reads as transparent rather than white */
.svo-canvas {
    position: relative;
    flex: 1 1 auto;
    min-height: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 1rem;
    /* A zoomed artboard is larger than its frame and has to be cut off at
       the edge rather than spilling over the neighbouring pane */
    overflow: hidden;
    background-color: #fff;
    background-image: repeating-conic-gradient(#e9e9e9 0% 25%, #ffffff 0% 50%);
    background-size: 20px 20px;
}

/* The artboard: image and difference mask in one box, transformed as one
   so they cannot drift apart when the view is zoomed.
   Its size is set in JS to the exact shape of the drawing - see
   layoutArt() - which is what makes the wipe's percentage a percentage of
   the picture rather than of a letterboxed frame around it. */
.svo-art {
    position: relative;
    flex: 0 0 auto;
    transform-origin: 0 0;
}

.svo-art img,
.svo-art canvas {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    object-fit: contain;
}

/* Zoomed in, the pointer moves the picture - except on the wipe divider,
   which has its own grab area */
.svo-zoomed .svo-canvas {
    cursor: grab;
}

.svo-dragging .svo-canvas {
    cursor: grabbing;
}


.svo-pane figcaption {
    flex: 0 0 auto;
    padding: 0.25rem 0.75rem;
    font-size: 0.75rem;
    color: var(--gn-muted);
    border-top: 1px solid var(--gn-card-border);
    text-align: center;
}

/* Wipe and Difference put both files in the same frame, so the left pane
   steps aside and the right one takes the width */
.svo-panes[data-view="wipe"] #svoPaneBefore,
.svo-panes[data-view="diff"] #svoPaneBefore {
    display: none;
}

.svo-panes[data-view="wipe"] #svoPaneAfter figcaption::after {
    content: " - drag to compare";
}

/* The optimized file is clipped at the wipe line (set in JS, on the
   element itself), with the original showing through from the layer
   behind it. The hint gets it a compositing layer of its own, so moving
   the line does not re-rasterize the SVG on every frame. */
.svo-panes[data-view="wipe"] #svoImgAfter {
    will-change: clip-path;
}

.svo-ghost {
    display: none;
}

.svo-panes[data-view="wipe"] .svo-ghost {
    display: block;
}

/* A grab area wide enough for a pointer, with the line drawn inside it.
   It has to be grabbable rather than the whole frame, because a drag in
   the frame pans a zoomed-in view. */
.svo-wipe-handle {
    position: absolute;
    top: 0;
    bottom: 0;
    width: 24px;
    margin-left: -12px;
    cursor: col-resize;
    touch-action: none;
}

.svo-wipe-handle::before {
    content: "";
    position: absolute;
    top: 0;
    bottom: 0;
    left: 50%;
    width: 2px;
    margin-left: -1px;
    background-color: var(--gn-accent);
}

.svo-wipe-handle span {
    position: absolute;
    top: 50%;
    left: 50%;
    width: 26px;
    height: 26px;
    transform: translate(-50%, -50%);
    border-radius: 50%;
    background-color: var(--gn-accent);
    box-shadow: 0 2px 8px rgba(0, 0, 0, 0.3);
}

/* The mask is a raster of which pixels changed, so magnifying it should
   show bigger pixels - smoothing would invent differences that are not
   there and blur away single-pixel ones that are */
.svo-diff {
    image-rendering: pixelated;
}

/* --- Results bar --------------------------------------------------- */

.svo-results {
    flex: 0 0 auto;
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.5rem 1rem;
    padding: 0.5rem 0.75rem;
    border-top: 1px solid var(--gn-card-border);
    background-color: var(--gn-card-bg);
}

.svo-sizes {
    display: flex;
    align-items: baseline;
    gap: 0.5rem;
    font-size: 0.9rem;
}

.svo-size-from {
    color: var(--gn-muted);
}

.svo-size-to {
    font-weight: 600;
}

.svo-saving {
    padding: 0.125rem 0.5rem;
    border-radius: 1rem;
    font-size: 0.75rem;
    font-weight: 600;
    color: #0a6b3d;
    background-color: #d8f3e3;
}

.svo-saving-none {
    color: var(--gn-muted);
    background-color: var(--gn-sidebar-hover-bg);
}

[data-bs-theme="dark"] .svo-saving {
    color: #6ee7a8;
    background-color: #103527;
}

[data-bs-theme="dark"] .svo-saving-none {
    color: var(--gn-muted);
    background-color: var(--gn-sidebar-hover-bg);
}

.svo-gzip {
    font-size: 0.75rem;
    color: var(--gn-muted);
}

/* The verdict is a button: it opens the numbers behind itself */
.svo-verdict {
    display: flex;
    align-items: center;
    gap: 0.375rem;
    margin-left: auto;
    padding: 0.25rem 0.625rem;
    border: 1px solid transparent;
    border-radius: 1rem;
    font-size: 0.8rem;
    background-color: var(--gn-sidebar-hover-bg);
    color: var(--gn-body-color);
}

.svo-verdict-identical {
    color: #0a6b3d;
    background-color: #d8f3e3;
    border-color: #a7e0c3;
}

.svo-verdict-edges {
    color: #7a5200;
    background-color: #fdf2d8;
    border-color: #efd9a0;
}

.svo-verdict-different,
.svo-verdict-blank,
.svo-verdict-unscalable,
.svo-verdict-unrenderable {
    color: #a01c2c;
    background-color: #fbe3e6;
    border-color: #f0b7bf;
}

[data-bs-theme="dark"] .svo-verdict-identical {
    color: #6ee7a8;
    background-color: #103527;
    border-color: #1c5d43;
}

[data-bs-theme="dark"] .svo-verdict-edges {
    color: #f5cf7a;
    background-color: #35290f;
    border-color: #5c4a1e;
}

[data-bs-theme="dark"] .svo-verdict-different,
[data-bs-theme="dark"] .svo-verdict-blank,
[data-bs-theme="dark"] .svo-verdict-unscalable,
[data-bs-theme="dark"] .svo-verdict-unrenderable {
    color: #ffa8b4;
    background-color: #3a1a20;
    border-color: #6b2c36;
}

.svo-verdict-detail {
    flex: 1 0 100%;
    margin: 0;
    font-size: 0.8rem;
    color: var(--gn-muted);
}

.svo-verdict-detail p {
    margin: 0 0 0.25rem;
}

.svo-verdict-sizes {
    font-variant-numeric: tabular-nums;
}

.svo-verdict-notes strong {
    color: var(--gn-body-color);
}

/* --- Code ---------------------------------------------------------- */

.svo-code {
    flex: 0 0 34%;
    min-height: 170px;
    display: flex;
    flex-direction: column;
    border-top: 1px solid var(--gn-card-border);
    background-color: var(--gn-card-bg);
}

.svo-code-bar {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    padding: 0.5rem 0.75rem;
    border-bottom: 1px solid var(--gn-card-border);
}

.svo-pretty .form-check-label {
    font-size: 0.8rem;
    color: var(--gn-muted);
    white-space: nowrap;
}

.svo-code-note {
    margin: 0;
    padding: 0.5rem 0.75rem 0;
    font-size: 0.75rem;
    line-height: 1.4;
    color: var(--gn-muted);
}

.svo-code-text {
    flex: 1 1 auto;
    min-height: 0;
    margin: 0;
    padding: 0.75rem;
    overflow: auto;
    font-size: 0.8rem;
    line-height: 1.5;
    white-space: pre-wrap;
    word-break: break-all;
    color: var(--gn-body-color);
}

/* --- Panel --------------------------------------------------------- */

.svo-panel {
    flex: 0 0 320px;
    border-left: 1px solid var(--gn-card-border);
}

.svo-label {
    font-size: 0.8rem;
    color: var(--gn-muted);
    margin-bottom: 0;
    margin-top: 0.75rem;
    display: block;
}

/* A label and its question mark on one line. The explanation itself is one
   click away instead of three lines of panel that only help the first time */
.svo-label-row {
    display: flex;
    align-items: center;
    gap: 0.375rem;
    margin-top: 0.75rem;
}

.svo-label-row .svo-label {
    /* Only as wide as its words, so the question mark sits against the
       heading rather than drifting off to the far edge */
    flex: 0 1 auto;
    min-width: 0;
    margin-top: 0;
}

.svo-help {
    flex: 0 0 auto;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 20px;
    height: 20px;
    padding: 0;
    border: 0;
    border-radius: 50%;
    background: none;
    color: var(--gn-muted);
    font-size: 0.85rem;
    line-height: 1;
}

.svo-help:hover,
.svo-help-open {
    color: var(--gn-accent);
}

.svo-help:focus-visible {
    outline: 2px solid var(--gn-accent);
    outline-offset: 1px;
}

/* The size to hit and the button that goes for it: two halves of one
   row, equal width, so neither reads as an afterthought of the other */
.svo-target-row {
    /* Grid, not flex: a flex basis of zero still has the button's padding
       and border added on top of it, which made it 18px wider than the
       field. Two equal tracks size the halves themselves. */
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 0.5rem;
}

.svo-target-row > * {
    min-width: 0;
}

/* The target-size line is empty until there is a result to report */
.svo-hint:empty {
    display: none;
}

.svo-val {
    color: var(--gn-accent);
    font-weight: 600;
}

.svo-hint {
    margin: 0.25rem 0 0;
    font-size: 0.72rem;
    line-height: 1.4;
    color: var(--gn-muted);
}

.svo-sep {
    margin: 1rem 0 0.5rem;
    border-color: var(--gn-card-border);
    opacity: 1;
}

.svo-group {
    margin-bottom: 1rem;
}

.svo-group-title {
    font-size: 0.75rem;
    font-weight: 600;
    color: var(--gn-accent);
    border-bottom: 1px solid var(--gn-card-border);
    padding-bottom: 3px;
    margin-bottom: 0.375rem;
}

/* Each step is a row: the toggle, and what it did. The result column is
   the report - there is no separate one. */
.svo-pass {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    gap: 0.5rem;
    padding: 0.125rem 0;
}

.svo-pass .form-check {
    flex: 1 1 auto;
    min-width: 0;
    margin: 0;
}

.svo-pass .form-check-label {
    font-size: 0.82rem;
    line-height: 1.3;
}

.svo-pass-result {
    flex: 0 0 auto;
    font-size: 0.72rem;
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}

.svo-pass-did {
    color: var(--gn-accent);
    font-weight: 600;
}

.svo-pass-none,
.svo-pass-off {
    color: var(--gn-muted);
    opacity: 0.7;
}

.svo-pass-why {
    /* A full-width basis PLUS a left margin is wider than the row it sits
       in, and 24px of panel scrolled sideways because of it. The margin
       comes out of the basis instead. */
    flex: 1 0 calc(100% - 1.5rem);
    margin: 0 0 0.375rem 1.5rem;
    font-size: 0.7rem;
    line-height: 1.35;
    color: var(--gn-muted);
}

.svo-group-risky .svo-group-title {
    color: #a01c2c;
}

[data-bs-theme="dark"] .svo-group-risky .svo-group-title {
    color: #ffa8b4;
}

.svo-warnings {
    padding: 0.5rem 0.625rem;
    border-radius: 0.375rem;
    background-color: #fdf2d8;
    color: #7a5200;
    font-size: 0.75rem;
}

.svo-warnings p {
    margin: 0;
}

[data-bs-theme="dark"] .svo-warnings {
    background-color: #35290f;
    color: #f5cf7a;
}

/* --- Welcome and drop zone ----------------------------------------- */

.svo-welcome {
    position: absolute;
    inset: 0;
    z-index: 8;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 1.5rem;
    background-color: var(--gn-body-bg);
}

.svo-welcome-card {
    max-width: 26rem;
    text-align: center;
}

.svo-welcome-icon {
    display: block;
    font-size: 3rem;
    color: var(--gn-accent);
    margin-bottom: 0.5rem;
}

.svo-welcome-actions {
    display: flex;
    flex-wrap: wrap;
    gap: 0.5rem;
    justify-content: center;
    margin-top: 1rem;
}

/* A file is over the window */
.svo-dropping::after {
    content: "Drop to optimize";
    position: absolute;
    inset: 0.5rem;
    z-index: 20;
    display: flex;
    align-items: center;
    justify-content: center;
    border: 2px dashed var(--gn-accent);
    border-radius: 0.75rem;
    background-color: color-mix(in srgb, var(--gn-body-bg) 88%, transparent);
    color: var(--gn-accent);
    font-weight: 600;
    pointer-events: none;
}

/* Until a file is loaded there is nothing to show or say */
.svo-app:not(.svo-loaded) .svo-panel,
.svo-app:not(.svo-loaded) .svo-code,
.svo-app:not(.svo-loaded) .svo-results {
    display: none;
}

.svo-paste-area {
    font-family: var(--bs-font-monospace);
    font-size: 0.8rem;
}

/* --- Small screens -------------------------------------------------- */

@media (max-width: 767px) {
    .svo-app {
        flex-direction: column;
        overflow-y: auto;
    }

    /* The stage steps out of the layout so its three parts become direct
       children of the scrolling app. That lets the results bar - the sizes
       and the verdict - stick to the top on its own while the pictures
       scroll away above it, so toggling a step still shows its answer
       without scrolling back up. */
    .svo-stage {
        display: contents;
    }

    .svo-views {
        flex: 0 0 auto;
        height: 38vh;
    }

    /* The results bar already wraps to two rows on a phone; the name is
       the least useful thing to give it a third for - you just picked it */
    .svo-file {
        display: none;
    }

    /* Clear of the caption strip. The control is small enough now to sit
       inside one pane at its normal size, so nothing else has to change */
    .svo-zoom-fabs {
        right: 0.75rem;
        bottom: 2rem;
    }

    .svo-results {
        position: sticky;
        top: 0;
        z-index: 5;
    }

    .svo-code {
        flex: 0 0 auto;
        height: 34vh;
    }

    .svo-panel {
        flex: 0 0 auto;
        border-left: 0;
        border-top: 1px solid var(--gn-card-border);
    }

    .svo-panel .app-side-body {
        overflow-y: visible;
    }

}
