* {
    margin: 0;
    padding: 0;
    box-sizing: border-box;
}

html, body {
    height: 100%;
}

body {
    font-family: var(--font-sans);
    background: var(--bg);
    color: var(--text);
    font-size: var(--text-base);
    -webkit-font-smoothing: antialiased;
}

a {
    color: inherit;
}

button, select, input {
    font-family: inherit;
    font-size: inherit;
    color: inherit;
}

::-webkit-scrollbar {
    width: 10px;
    height: 10px;
}
::-webkit-scrollbar-track {
    background: transparent;
}
::-webkit-scrollbar-thumb {
    background: var(--scrollbar);
    border-radius: var(--radius-sm);
}

:focus-visible {
    outline: 2px solid var(--focus-ring);
    outline-offset: 2px;
}

.app-shell {
    display: grid;
    grid-template-columns: var(--sidebar-width) 1fr;
    min-height: 100vh;
}

/* Collapsed sidebar (desktop). The state lives on <html> rather than on .app-shell so the
   inline head script in base.html can set it before first paint -- .app-shell does not
   exist yet at that point. Only the grid column changes here; what the rail itself looks
   like is with the rest of the sidebar in components.css.

   Neither the query nor the :not() is tidiness -- both exist because this selector outweighs
   a plain single-class rule, and there are two such rules it must not beat:

     .app-shell inside the max-width: 900px query. Below the breakpoint the sidebar is a
     fixed-position drawer and the grid is meant to be one column; unscoped, this would
     reserve a 64px column on a phone for a sidebar that is no longer in the flow. 901px is
     the complement of the max-width: 900px queries below; the two must move together.

     .app-shell--bare, the framed page. That document has NO sidebar -- the chrome is the
     shell's, around the frame -- but it is same-origin, so its own copy of the head script
     reads the same preference and stamps the same attribute. Unscoped, collapsing the
     sidebar squeezed every framed page into a 64px content column: the whole app, since
     framed is the ordinary path. The frame is the one place where "collapsed" has nothing
     to say, because there is no sidebar there to collapse. */
@media (min-width: 901px) {
    :root[data-sidebar="collapsed"] .app-shell:not(.app-shell--bare) {
        grid-template-columns: var(--sidebar-width-collapsed) 1fr;
    }
}

.app-shell__main {
    display: flex;
    flex-direction: column;
    min-width: 0;
}

/* One width for every page. Packages used to opt into a wider cap on its own because its
   table carries full download URLs, step chains and a three-button action column, but a
   page that is narrower than its neighbours reads as a bug rather than as restraint: the
   sidebar stays put and the content jumps in from the right edge on every other tab. Prose
   that shouldn't run the full 1600px sets its own measure in ch on the block itself (see
   .backup-intro in backups.css) rather than squeezing the whole page. */
.app-shell__content {
    flex: 1;
    padding: var(--space-6) var(--space-8);
    max-width: 1600px;
    width: 100%;
}

/* The app shell (static/js/shell.js): chrome that stays, pages in a frame under it.

   height, not min-height: the frame has to be given a definite box to fill, and the scrolling
   belongs to the document inside it. Letting the shell scroll as well is what produces the
   two-scrollbar look, hence overflow: hidden. */
.app-shell--frames {
    height: 100vh;
    overflow: hidden;
}

.app-shell--frames .app-shell__main {
    min-height: 0;   /* or the frame's overflow pushes the flex column past the viewport */
}

.app-frames {
    flex: 1;
    min-height: 0;
    display: flex;
}

.app-frames__frame {
    flex: 1;
    width: 100%;
    border: 0;
    display: block;
}

/* Not redundant: `display: block` above would otherwise beat the [hidden] attribute's UA
   rule, and every background frame -- the whole point of the shell -- would be on screen. */
.app-frames__frame[hidden] {
    display: none;
}

/* The same page rendered inside that frame. The chrome is already on screen around it, so
   the grid has one column and no sidebar to reserve room for; everything else about the
   content column is unchanged, which is why pages need no framed-only styles of their own. */
.app-shell--bare {
    grid-template-columns: 1fr;
}

@media (max-width: 900px) {
    .app-shell {
        grid-template-columns: 1fr;
    }
    .app-shell__content {
        padding: var(--space-4);
    }
    /* Hiding .sidebar lives with the rest of its styles in components.css -- putting it
       here silently did nothing, since that file loads later and media queries add no
       specificity. */
}
