/* ==========================================================================
   Printable Graph Paper — the studio
   A three-pane app: every paper type on the left, the sheet in the middle
   with its ways out underneath, the settings on the right. Loaded only on
   pages that carry a generator.
   ========================================================================== */

/* --------------------------------------------------------------------------
   1. The app frame
   ----------------------------------------------------------------------------
   One bordered box, tall enough to show a whole portrait sheet on a laptop
   screen. The side list and the settings scroll inside it; the page itself
   only scrolls to reach the articles below.
   -------------------------------------------------------------------------- */
/* One screen-high workspace, like a desktop app: the three panes share its
   height, the sheet always shows whole with Download under it, and nothing
   is pinned — so nothing slides along beside the page as it scrolls on to
   the articles below. The paper list and the settings scroll inside their
   own panes only when they run longer than it, and let the page take over
   the wheel at their ends rather than trapping it.

   --app-top is everything above the app — header, breadcrumbs, heading —
   so the whole workspace fits the first screen. The studio script measures
   it on load; the value here is a close guess for the first paint. */
.app {
    --app-top: 268px;
    --app-h: clamp(560px, calc(100vh - var(--app-top) - 16px), 960px);
    display: grid;
    grid-template-columns: 232px minmax(0, 1fr) 330px;
    height: var(--app-h);
    border: 1px solid var(--line);
    border-radius: 14px;
    background: var(--surface);
    overflow: hidden;
    margin-bottom: 56px;
}

/* The home page has no breadcrumbs and a one-line lede. */
.intro--home + .app {
    --app-top: 214px;
}

/* --------------------------------------------------------------------------
   2. Paper list
   -------------------------------------------------------------------------- */
.side {
    min-height: 0;
    overflow-y: auto;
    scrollbar-width: thin;
    border-inline-end: 1px solid var(--line);
    background: var(--surface);
}

/* The search box stays at hand however far down the list is scrolled. */
.side__head {
    position: sticky;
    top: 0;
    z-index: 2;
    padding: 12px;
    border-bottom: 1px solid var(--line-soft);
    background: var(--surface);
}

.side__scroll {
    padding: 4px 8px 16px;
}

/* A category heading that folds its papers away, one group open at a time. */
.side__summary {
    display: flex;
    align-items: center;
    gap: 8px;
    margin-top: 6px;
    padding: 8px;
    border-radius: 8px;
    list-style: none;
    cursor: pointer;
    user-select: none;
}

.side__summary::-webkit-details-marker {
    display: none;
}

.side__summary:hover {
    background: var(--surface-2);
}

/* A chevron pointing along the reading direction while folded, down once
   open. */
.side__summary::after {
    content: "";
    width: 6px;
    height: 6px;
    flex: none;
    border: solid var(--muted);
    border-width: 0 1.5px 1.5px 0;
    transform: rotate(-45deg);
    transition: transform .15s ease;
}

[dir="rtl"] .side__summary::after {
    transform: rotate(135deg);
}

.side__group[open] > .side__summary::after {
    transform: rotate(45deg);
}

.side__title {
    font-size: .7rem;
    text-transform: uppercase;
    letter-spacing: .08em;
    color: var(--muted);
    font-weight: 600;
    margin: 0;
}

.side__group[open] .side__title {
    color: var(--ink);
}

.side__count {
    margin-inline-start: auto;
    font-size: .72rem;
    color: var(--muted);
    font-variant-numeric: tabular-nums;
}

.side__group[open] > .side__summary {
    margin-bottom: 2px;
}

.side__empty {
    color: var(--muted);
    font-size: .85rem;
    padding: 12px 8px;
    margin: 0;
}

.type {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 6px 8px;
    border-radius: 8px;
    color: var(--ink);
    text-decoration: none;
    font-size: .88rem;
    line-height: 1.25;
}

.type:hover {
    background: var(--surface-2);
}

.type.on {
    background: var(--accent-soft);
    color: var(--accent);
    font-weight: 600;
}

.type i {
    width: 22px;
    height: 22px;
    flex: none;
    border: 1px solid var(--line-soft);
    border-radius: 4px;
    background: #fff;
    overflow: hidden;
}

.type i svg,
.type i img {
    width: 100%;
    height: 100%;
    display: block;
}

/* --------------------------------------------------------------------------
   3. Canvas: the sheet on its stage, and the toolbar under it
   -------------------------------------------------------------------------- */
.canvas {
    container: canvas / inline-size;
    display: flex;
    flex-direction: column;
    min-width: 0;
    min-height: 0;
    background: var(--stage);
}

/* A size container, so the sheet can fit whichever of the pane's width and
   height runs out first — a portrait page and a landscape one both show
   whole, with no inner scrolling. */
.stage {
    position: relative;
    flex: 1;
    min-height: 0;
    display: grid;
    place-items: center;
    padding: 18px 20px;
    container-type: size;
    overflow: hidden;
}

.sheet-hold {
    display: flex;
    justify-content: center;
}

/* The sheet is always white: it is a picture of paper, and paper does not
   have a dark mode. --r is its height over its width. */
.sheet {
    --r: 1.4142;
    background: #fff;
    box-shadow: 0 0 0 1px rgba(16, 24, 40, .06), 0 8px 28px rgba(16, 24, 40, .12);
    width: min(calc(100cqw - 16px), calc((100cqh - 16px) / var(--r)), 620px);
    position: relative;
    border-radius: 1px;
}

.sheet svg,
.sheet img {
    display: block;
    width: 100%;
    height: auto;
}

/* Shown only until the first grid is painted. The sheet already occupies its
   final box by then, so this is reassurance rather than a placeholder that
   changes size. */
.sheet.is-loading {
    background:
        linear-gradient(100deg, transparent 20%, rgba(37, 99, 235, .06) 40%, transparent 60%),
        #fff;
    background-size: 240% 100%, 100% 100%;
    background-repeat: no-repeat;
    animation: sheet-shimmer 1.25s ease-in-out infinite;
}

@keyframes sheet-shimmer {
    from { background-position: 160% 0, 0 0; }
    to   { background-position: -60% 0, 0 0; }
}

/* A sheet that already shows its ready-made picture has nothing to wait for,
   and an animation left running behind it still costs the phone work. */
.sheet.is-loading:has(img) {
    animation: none;
    background: #fff;
}

@media (prefers-reduced-motion: reduce) {
    .sheet.is-loading {
        animation: none;
        background: #fff;
    }
}

.toolbar {
    flex: none;
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    padding: 10px 14px;
    border-top: 1px solid var(--line);
    background: var(--surface);
}

.dims {
    color: var(--muted);
    font-size: .78rem;
    white-space: nowrap;
}

.toolbar__actions {
    display: flex;
    align-items: center;
    gap: 8px;
    flex-wrap: wrap;
    justify-content: flex-end;
}

/* A narrow sheet pane — a tablet, or a small laptop window — keeps every
   action on one line: Print, PNG and SVG shrink to their icons (their names
   stay for screen readers and as tooltips), and the size readout gives way. */
/* Only where the actions sit in the toolbar: on a phone they move to the
   bar at the bottom of the screen, and the readout keeps its room. */
@media (min-width: 721px) {
    @container canvas (max-width: 560px) {
        .toolbar .dims {
            display: none;
        }

        .toolbar__actions {
            flex: 1;
            flex-wrap: nowrap;
        }

        .toolbar__actions .btn.ghost:has(svg) {
            padding-inline: 10px;
        }

        .toolbar__actions .btn.ghost:has(svg) span {
            position: absolute;
            width: 1px;
            height: 1px;
            overflow: hidden;
            clip-path: inset(50%);
            white-space: nowrap;
        }
    }
}

/* --------------------------------------------------------------------------
   4. Settings panel
   -------------------------------------------------------------------------- */
/* As tall as the workspace. With Customize open the settings scroll inside
   the pane, under a header that stays put, while the sheet beside them stays
   in view so every change is seen as it is made. */
.panel {
    min-height: 0;
    overflow-y: auto;
    scrollbar-width: thin;
    border-inline-start: 1px solid var(--line);
    background: var(--surface);
}

.panel__head {
    position: sticky;
    top: 0;
    z-index: 2;
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    padding: 12px 16px;
    background: var(--surface);
    border-bottom: 1px solid var(--line-soft);
}

.panel__head h2 {
    margin: 0;
    font-size: .74rem;
    text-transform: uppercase;
    letter-spacing: .08em;
    color: var(--muted);
    font-weight: 600;
}

.link-btn {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    background: none;
    border: 0;
    padding: 4px 6px;
    border-radius: 6px;
    color: var(--accent);
    font: inherit;
    font-size: .82rem;
    cursor: pointer;
}

.link-btn:hover {
    background: var(--accent-soft);
}

.link-btn svg {
    width: 14px;
    height: 14px;
}

.link-btn[disabled] {
    color: var(--muted);
    opacity: .5;
    cursor: default;
    pointer-events: none;
}

.quick {
    padding: 16px;
    display: grid;
    gap: 16px;
}

.q label,
.q .lab {
    display: block;
    font-size: .78rem;
    color: var(--muted);
    margin-bottom: 6px;
    font-weight: 500;
}

.q select {
    width: 100%;
    background: var(--surface);
    border: 1px solid var(--line);
    color: var(--ink);
    border-radius: 8px;
    padding: 9px 10px;
    font: inherit;
    font-size: .9rem;
    appearance: none;
    background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='10' height='6'><path d='M1 1l4 4 4-4' fill='none' stroke='%23889' stroke-width='1.6'/></svg>");
    background-repeat: no-repeat;
    background-position: right 10px center;
}

/* The type chips repeat the list beside them, so they appear only once the
   list has moved into the drawer. */
.q--types {
    display: none;
}

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

.chips a,
.chips button {
    border: 1px solid var(--line);
    background: var(--surface);
    color: var(--ink);
    border-radius: 999px;
    padding: 6px 12px;
    font: inherit;
    font-size: .84rem;
    cursor: pointer;
    white-space: nowrap;
    text-decoration: none;
}

.chips a {
    display: inline-flex;
    align-items: center;
    gap: 6px;
}

.chips a:hover,
.chips button:hover {
    border-color: var(--accent);
}

.chips a.more {
    border-style: dashed;
    color: var(--muted);
}

.chips a[aria-current="true"],
.chips button[aria-pressed="true"] {
    background: var(--accent);
    border-color: var(--accent);
    color: var(--accent-ink);
    font-weight: 600;
}

.note {
    margin: 0;
    padding: 14px 16px 18px;
    font-size: .75rem;
    color: var(--muted);
    border-top: 1px solid var(--line-soft);
}

/* --------------------------------------------------------------------------
   3c. Customize disclosure
   -------------------------------------------------------------------------- */
.customize {
    width: 100%;
    display: flex;
    align-items: center;
    gap: 9px;
    background: none;
    border: 0;
    border-top: 1px solid var(--line-soft);
    color: var(--ink);
    font: inherit;
    font-size: .9rem;
    font-weight: 600;
    padding: 14px 16px;
    cursor: pointer;
    text-align: left;
}

.customize:hover {
    color: var(--accent);
}

.customize svg {
    width: 16px;
    height: 16px;
    flex: none;
    color: var(--muted);
}

.customize .chev {
    margin-left: auto;
    transition: transform .2s ease;
}

.customize.is-open .chev {
    transform: rotate(180deg);
}

.fields {
    padding: 0 16px 16px;
    display: grid;
    gap: 14px;
    border-top: 1px solid var(--line-soft);
    padding-top: 14px;
}

.fieldset-title {
    font-size: .74rem;
    text-transform: uppercase;
    letter-spacing: .07em;
    color: var(--muted);
    border-top: 1px solid var(--line-soft);
    padding-top: 12px;
    margin-top: 2px;
}

.fieldset-title:first-child {
    border-top: 0;
    padding-top: 0;
    margin-top: 0;
}

.f label,
.f .lab {
    display: block;
    font-size: .79rem;
    color: var(--muted);
    margin-bottom: 5px;
}

.f select,
.f input[type=number],
.f input[type=text] {
    width: 100%;
    background: var(--surface-2);
    border: 1px solid var(--line);
    color: var(--ink);
    border-radius: 8px;
    padding: 8px 10px;
    font: inherit;
    font-size: .9rem;
}

.f select {
    appearance: none;
    background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='10' height='6'><path d='M1 1l4 4 4-4' fill='none' stroke='%23788' stroke-width='1.6'/></svg>");
    background-repeat: no-repeat;
    background-position: right 10px center;
}

.seg {
    display: flex;
    border: 1px solid var(--line);
    border-radius: 8px;
    overflow: hidden;
}

.seg button {
    flex: 1;
    background: var(--surface-2);
    border: 0;
    color: var(--muted);
    font: inherit;
    font-size: .85rem;
    padding: 8px 6px;
    cursor: pointer;
}

.seg button + button {
    border-left: 1px solid var(--line);
}

.seg button[aria-pressed="true"] {
    background: var(--accent);
    color: var(--accent-ink);
}

.rowline {
    display: flex;
    align-items: center;
    gap: 10px;
}

.rowline input[type=range] {
    flex: 1;
    accent-color: var(--accent);
    height: 22px;
}

.num {
    width: 74px;
    text-align: right;
    font-family: var(--mono);
    font-size: .84rem;
}

/* The unit a length is typed in, sitting against its number box. */
.f select.unit {
    width: auto;
    min-width: 72px;
    font-size: .78rem;
    padding: 5px 22px 5px 8px;
}

.rowline .by {
    color: var(--muted);
    font-size: .8rem;
}

.rowline input[type=number]:not(.num) {
    flex: 1;
    min-width: 0;
    text-align: right;
    font-family: var(--mono);
    font-size: .84rem;
}

/* Type a hex when a swatch will not do. It sits with the swatches, so it
   must not take the full-width treatment the other text inputs get. */
.f input.hex {
    flex: 0 0 auto;
    width: 90px;
    padding: 5px 8px;
    font-family: var(--mono);
    font-size: .78rem;
    text-transform: lowercase;
}

.swatches {
    display: flex;
    gap: 6px;
    flex-wrap: wrap;
    align-items: center;
}

.sw {
    width: 24px;
    height: 24px;
    border-radius: 6px;
    border: 1px solid rgba(0, 0, 0, .18);
    cursor: pointer;
    padding: 0;
}

.sw[aria-pressed="true"] {
    box-shadow: 0 0 0 2px var(--surface), 0 0 0 4px var(--accent);
}

input[type=color] {
    width: 28px;
    height: 28px;
    padding: 0;
    border: 1px solid var(--line);
    border-radius: 6px;
    background: none;
    cursor: pointer;
}

.chk {
    display: flex;
    align-items: center;
    gap: 9px;
    font-size: .86rem;
    color: var(--ink);
    margin-bottom: 0;
    cursor: pointer;
}

.chk input[type=checkbox] {
    width: 17px;
    height: 17px;
    flex: none;
    margin: 0;
    accent-color: var(--accent);
    cursor: pointer;
}

/* --------------------------------------------------------------------------
   6. Mobile action bar
   -------------------------------------------------------------------------- */
.mobbar {
    display: none;
}

/* --------------------------------------------------------------------------
   7. Responsive
   -------------------------------------------------------------------------- */
/* Laptop: the list moves into the drawer, and the type chips in the panel
   take its place for the few types most people want. */
@media (max-width: 1199px) {
    .app {
        grid-template-columns: minmax(0, 1fr) 320px;
    }

    .app > .side {
        display: none;
    }

    .q--types {
        display: block;
    }
}

/* Tablet: the sheet and the settings side by side, a little narrower. */
@media (max-width: 959px) {
    .app {
        grid-template-columns: minmax(0, 1fr) 300px;
    }
}

/* Phone, or a window too short to hold a workspace: one column that flows
   with the page. The sheet is sized by the width alone. */
@media (max-width: 720px), (max-height: 540px) {
    /* Stretch, not start: in a column that would size each pane to its
       content, and the stage — a size container, which has no content width
       of its own — would shrink the sheet to a thumbnail. */
    .app {
        display: flex;
        flex-direction: column;
        align-items: stretch;
        gap: 16px;
        height: auto;
        border: 0;
        border-radius: 0;
        background: none;
        overflow: visible;
        margin-bottom: 40px;
    }

    .app > .side {
        display: none;
    }

    .q--types {
        display: block;
    }

    /* On a paper's own page the sheet comes first, so the visitor sees what
       they came for, and the settings follow. The home page is a picker
       before it is a preview, so there the choices — type, size, spacing —
       lead. */
    .app--settings-first > .panel {
        order: -1;
    }

    .canvas {
        border-radius: 12px;
        overflow: hidden;
    }

    .stage {
        container-type: inline-size;
        padding: 16px 12px;
    }

    .sheet {
        width: min(calc(100cqw - 8px), 560px);
    }

    .toolbar {
        border: 0;
        background: none;
        padding: 0 12px 12px;
    }

    /* Nothing scrolls inside anything: every pane runs its full length. */
    .panel {
        overflow: hidden;
        border: 1px solid var(--line);
        border-radius: 12px;
    }

    .panel__head {
        position: static;
    }
}

/* Phone: the actions live in a bar fixed to the bottom. */
@media (max-width: 720px) {
    body {
        padding-bottom: 70px;
    }

    .toolbar__actions {
        display: none;
    }

    .mobbar {
        display: flex;
        gap: 8px;
        position: fixed;
        left: 0;
        right: 0;
        bottom: 0;
        z-index: 70;
        background: var(--surface);
        border-top: 1px solid var(--line);
        padding: 9px 14px calc(9px + env(safe-area-inset-bottom));
    }

    .mobbar .btn {
        padding: 11px 14px;
    }

    .mobbar .btn:not(.ghost) {
        flex: 1;
    }
}


/* --------------------------------------------------------------------------
   8. Virtual graph paper
   ----------------------------------------------------------------------------
   The same frame as the generator; the sheet carries the grid as an SVG and
   the ink on a canvas laid exactly over it.
   -------------------------------------------------------------------------- */
.sheet--draw {
    background: #fff;
}

.sheet__grid,
.sheet__grid svg,
.sheet--draw canvas {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    display: block;
}

.sheet--draw canvas {
    cursor: crosshair;
    touch-action: none;
}

.sheet--draw canvas[data-tool="eraser"] {
    cursor: cell;
}

.toolset {
    display: flex;
    flex-wrap: wrap;
    gap: 4px;
}

.tool {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    border: 1px solid var(--line);
    background: var(--surface);
    color: var(--ink);
    border-radius: 8px;
    padding: 6px 10px;
    font: inherit;
    font-size: .84rem;
    cursor: pointer;
}

.tool:hover {
    border-color: var(--ink);
}

.tool[aria-pressed="true"] {
    background: var(--ink);
    border-color: var(--ink);
    color: var(--bg);
}

@media (max-width: 959px) {
    .app--draw .toolbar {
        flex-wrap: wrap;
    }

    .app--draw .toolbar__actions {
        display: flex;
    }
}
