/* The app shell every tool shares (Alpha 8.72): the corner bar over the side list, the tool header beside it and the main pane
   under it. Markup and rules: docs/project/app-shell.md. chat.css, pages.css and every tool's own css sit on top of this file. */
html, body { height: 100%; margin: 0; }
/* The app shell never scrolls as a page (its panes scroll inside); this also keeps the frost layers of the panes at the
   screen edges from adding scroll room */
html, body { overflow-y: clip; }
@supports (height: 100dvh) { html, body { height: 100dvh; } }
body { overscroll-behavior: none; -webkit-tap-highlight-color: transparent; }
body { font-size: 17px; line-height: 1.5; display: flex; gap: 14px; padding: 14px; }
/* A page that also loads pages.css (forms, buttons) would centre its body in a grid: the frame fills the screen instead */
body { min-height: 0; place-items: stretch; }

#sidebar {
  width: var(--sidebar-width); flex-shrink: 0; align-self: flex-start; max-height: 100%; border-radius: var(--radius-card); --glass-radius: var(--radius-card);
  display: flex; flex-direction: column; color: var(--ui-text); position: relative; z-index: 2;
}
#sidebar .top { padding: 12px 12px 8px; }
#sidebar .top button { width: 100%; height: 44px; display: flex; align-items: center; justify-content: center; gap: 8px; padding: 0 14px; }

#main { flex: 1; display: flex; flex-direction: column; gap: 12px; min-width: 0; position: relative; z-index: 1; }
header {
  display: flex; align-items: center; gap: 6px; border-radius: var(--radius-control); --glass-radius: 31px;
  min-height: 60px; padding: 8px 10px 8px 12px; color: var(--ui-text);
}
header h1 { display: flex; align-items: center; gap: 11px; font: 600 28px/1 var(--font-display); letter-spacing: .01em; margin: 0; flex: 0 1 auto; min-width: 0; white-space: nowrap; color: var(--ui-title); }
header h1 > span:last-child, header h1 { overflow: hidden; text-overflow: ellipsis; }
.brand-tile {
  width: 40px; height: 40px; flex-shrink: 0; border-radius: 50%; display: grid; place-items: center; color: #fff;
  background-color: color-mix(in srgb, var(--brand-light) 40%, rgb(255 255 255 / .1));
  background-image: radial-gradient(120% 90% at 30% 12%, rgb(255 255 255 / .5), rgb(255 255 255 / 0) 55%);
  box-shadow: inset 0 1px 0 rgb(255 255 255 / .6), inset 0 0 0 1px rgb(255 255 255 / .34), 0 2px 6px rgb(0 0 0 / .2);
}
.brand-tile svg { width: 18px; height: 18px; }
.icon { width: 18px; height: 18px; display: block; }
#toggle-sidebar, #attach, .from-hollowkeep { display: grid; place-items: center; }
header a {
  display: inline-flex; align-items: center; gap: 7px; height: 38px; padding: 0 12px; border-radius: var(--radius-control);
  color: var(--ui-text-soft); font-size: 15px; text-decoration: none; white-space: nowrap;
}
@media (hover: hover) { header a:hover { color: var(--ui-text); background: rgb(255 255 255 / .1); } }
header .header-button { height: var(--button); padding: 0 14px; }
header .header-button[hidden] { display: none; }
.chat-head { flex: 1; min-width: 0; display: flex; align-items: center; gap: 10px; }
.prefs { display: flex; align-items: center; gap: 2px; flex: none; }
.prefs { margin-left: 6px; padding-left: 8px; border-left: 1px solid var(--lg-hairline); }
#toggle-sidebar { display: none; place-items: center; width: 40px; height: 40px; padding: 0; border-radius: 50%; }

@media (max-width: 760px) {
  body { padding: 0; gap: 0; }
  #main { gap: 0; }
  header { border-radius: 0; --glass-radius: 0px; border-left: none; border-right: none; }
  header { border-top: none; }
  #sidebar { position: fixed; inset: calc(62px + var(--safe-top, 0px)) auto calc(8px + var(--safe-bottom, 0px)) 8px; z-index: 10; max-height: none; border-radius: var(--radius-card); --glass-radius: var(--radius-card); transform: translateX(-120%); transition: transform .3s var(--ease); background: var(--sheen), var(--glass-thick); }
  body.sidebar-open #sidebar { transform: none; }
  /* A drawer that only sized to its list would be pushed up over the header once the list is longer than the screen
     (a fixed box with align-self: flex-start keeps its own height); it fills the room between header and bottom instead */
  body #sidebar { align-self: stretch; max-height: none; }
  #toggle-sidebar { display: grid; }
  /* The side list as a drawer is a popup: no frost hanging out of it, no swipe handed on to the page behind */
  body #sidebar { --frost-reach: 0px; overscroll-behavior: contain; }
}
/* Short screens (phones on their side): the side list folds into the header's list button as on narrow screens, and the
   header sits beside the corner bar (header.js), so the pane gets the whole height under one 44px row */
@media (max-height: 560px) and (min-width: 521px) {
  body { gap: 8px; padding: calc(8px + var(--safe-top, 0px)) calc(8px + env(safe-area-inset-right, 0px)) calc(8px + var(--safe-bottom, 0px)) calc(8px + env(safe-area-inset-left, 0px)); }
  #main { gap: 8px; }
  #sidebar { position: fixed; z-index: 10; inset: calc(60px + var(--safe-top, 0px)) auto calc(8px + var(--safe-bottom, 0px)) calc(8px + env(safe-area-inset-left, 0px)); align-self: stretch; max-height: none; border-radius: var(--radius-card); --glass-radius: var(--radius-card); transform: translateX(-120%); transition: transform .3s var(--ease); background: var(--sheen), var(--glass-thick); }
  body.sidebar-open #sidebar { transform: none; }
  #toggle-sidebar { display: grid; width: var(--button-small); height: var(--button-small); }
  body #sidebar { --frost-reach: 0px; overscroll-behavior: contain; }
}
@media (max-width: 480px) {
  header { gap: 2px; padding: 8px 6px 8px 10px; }
  header h1 { font-size: 20px; gap: 8px; }
  #toggle-sidebar { width: 36px; height: 36px; }
  header a, header .header-button { height: var(--button-small); padding: 0 7px; }
  .brand-tile { width: 28px; height: 28px; }
  .brand-tile svg { width: 15px; height: 15px; }
  header a { padding: 0 8px; }
  .chat-head { gap: 4px; }
  .prefs { margin-left: 2px; padding-left: 4px; }
  /* The page itself never scrolls on a phone: the body is pinned to the screen, so an installed app that misreports its
     height (iOS 27) still shows the chat from the top bar to the bottom bar, and nothing drifts when you drag */
  html { overflow: hidden; }
  body { position: fixed; inset: 0; width: 100%; height: auto; overflow: hidden; }
  /* The keyboard is up (header.js followKeyboard): iOS pans the visual viewport over the layout and does not shrink it, so the
     pinned frame is sized to the visual viewport and placed at its offset; the composer then stays on the keyboard */
  html.kb-open body { top: var(--vvt, 0px); bottom: auto; height: var(--vvh, 100%); }
}
@media (max-width: 520px) {
  /* The phone's fixed bars follow the visual viewport's offset while the keyboard pans it, so they do not slide off the screen */
  html.kb-open :is(.seppo-bar, .seppo-corner, .seppo-tool-head, .phone-band, [data-seppo-bar="app"] #main > header) { translate: 0 var(--vvt, 0px); }
}

#sidebar .top button { gap: 9px; }

/* The side list: places (a link with an icon; the open one is lit), small headings and a foot with a meter or a note.
   A tool names its colour once with --tool-accent (the open place's icon). Tools that are not a list of chats use these
   instead of drawing their own rows. */
.places-list { display: grid; gap: 2px; padding: 2px 8px 6px; }
.place {
  display: flex; align-items: center; gap: 10px; padding: 10px 12px; border-radius: var(--radius-small);
  color: var(--ui-text-soft); text-decoration: none; font-size: 15.5px;
}
.place .icon { width: 19px; height: 19px; }
@media (hover: hover) { .place:hover { background: color-mix(in srgb, white 7%, transparent); color: var(--ui-text); } }
.place[aria-current] { background: color-mix(in srgb, white 9%, transparent); color: var(--ui-text); box-shadow: inset 0 0 0 1px var(--edge), var(--rim); }
.place[aria-current] .icon { color: var(--tool-accent, var(--ui-highlight)); }
.side-heading { margin: 12px 14px 4px; font: 700 11.5px/1.2 var(--font-label); letter-spacing: .12em; text-transform: uppercase; color: var(--ui-label); }
.side-foot button { width: 100%; height: 40px; display: flex; align-items: center; justify-content: center; gap: 9px; padding: 0 12px; }
.side-foot { margin: 0 12px 14px; padding: 12px 4px 0; border-top: var(--lead-w) solid var(--lead); font-size: 13.5px; color: var(--ui-text-soft); }

/* The main pane: the one window under the header, as wide as the header and as tall as what is left. It holds the glass; what is
   inside scrolls (a scrolling glass box would clip its frost). A tool puts its page, list or canvas in it. */
.shell-pane { position: relative; flex: 1; min-height: 0; display: flex; flex-direction: column; border-radius: var(--radius-panel); --glass-radius: var(--radius-panel); overflow: hidden; }
.shell-pane > .shell-scroll { flex: 1; min-height: 0; overflow-y: auto; overscroll-behavior: contain; padding: 22px 24px 28px; }
@media (max-width: 480px) { .shell-pane > .shell-scroll { padding: 16px 14px 20px; } }

/* Workspace: plain type sizes, rows like a file browser, no glows (DESIGN.md, Workspace) */
:root[data-scene="workspace"] .place { padding: 6px 10px; font-size: 14px; }
:root[data-scene="workspace"] .place .icon { width: 16px; height: 16px; }
@media (hover: hover) { :root[data-scene="workspace"] .place:hover { background: var(--ws-row-hover); text-decoration: none; } }
:root[data-scene="workspace"] .place[aria-current] { background: var(--ws-selected); box-shadow: inset 2px 0 0 var(--ui-highlight); color: var(--ui-title); }

/* The tool name in the header with its one-line description under it */
header .app-name { display: flex; flex-direction: column; gap: 3px; min-width: 0; overflow: hidden; text-overflow: ellipsis; }
header .app-name small { font: 500 13px/1.25 var(--font-body); letter-spacing: .02em; color: var(--ui-text-soft); overflow: hidden; text-overflow: ellipsis; }
@media (max-width: 760px) { header .app-name small.tool-description { display: none; } }

/* A side list of folding groups (settings, filters): <div class="side-scroll"> of <details class="side-group"> with a
   <summary class="side-heading"> and a <div class="side-group-body">. The list scrolls inside the sidebar. */
#sidebar { min-height: 0; }
.side-scroll { flex: 1; min-height: 0; overflow-x: hidden; overflow-y: auto; overscroll-behavior: contain; padding-bottom: 8px; }
.side-group + .side-group { border-top: var(--lead-w) solid var(--lead); }
.side-group > summary.side-heading { list-style: none; display: flex; align-items: center; justify-content: space-between; margin: 0; padding: 12px 14px 8px; cursor: pointer; }
.side-group > summary.side-heading::-webkit-details-marker { display: none; }
.side-group > summary.side-heading::after { content: ""; width: 7px; height: 7px; border-right: 2px solid currentColor; border-bottom: 2px solid currentColor; transform: rotate(-45deg); transition: transform .2s; }
.side-group[open] > summary.side-heading::after { transform: rotate(45deg); }
.side-group-body { padding: 2px 12px 12px; display: grid; gap: 8px; }
.side-group-body > * { min-width: 0; }
/* A long side list (the admin pages of the login service) scrolls inside the glass; the glass stays where it is. A place that
   leaves the site part (code, docs) carries a small arrow at its end. */
#sidebar .places-list { min-height: 0; overflow-x: hidden; overflow-y: auto; overscroll-behavior: contain; }
.place .outside { margin-left: auto; font-size: .8em; opacity: .7; }

/* Phones with the bottom bar: the side list opens as the same glass sheet above the bar that the chat tools' drawer is (drawer.css), so the
   bar's left button looks and behaves the same on every page. A tap beside it closes it (shell.js). */
@media (max-width: 520px) and (min-height: 501px) {
  html.tabbar-page body #sidebar {
    position: fixed; z-index: 39; inset: auto 10px calc(76px + var(--safe-bottom, 0px)) 10px; width: auto; align-self: auto;
    max-height: min(620px, calc(100svh - 150px - var(--safe-top, 0px))); border-radius: var(--radius-card); --glass-radius: var(--radius-card);
    background: var(--sheen), var(--glass-thick); transform: translateY(14px); visibility: hidden; overflow: hidden; --frost-reach: 0px; overscroll-behavior: contain; touch-action: pan-y;
    transition: transform .26s var(--ease, ease-out), visibility 0s .26s;
  }
  html.tabbar-page body.sidebar-open #sidebar { transform: none; visibility: visible; transition-delay: 0s; }
  html.tabbar-page body.sidebar-open::before { content: ""; position: fixed; z-index: 38; inset: 0; background: rgb(8 8 12 / .3); }
}
@media (max-width: 520px) and (min-height: 501px) and (prefers-reduced-motion: reduce) { html.tabbar-page body #sidebar { transition: none; } }

/* The tool's one-line description under its name in the header is a tooltip now (less text, 2026-10-20): the name says it */
header .app-name small.tool-description { display: none !important; }

/* Document scroll (Sebastian's mobile research, rank 1), ON by default on phones; off with html.no-doc-scroll. On a phone the page itself scrolls instead of the
   pinned frame's inner pane, so Safari's bar folding, the dynamic viewport and the keyboard pan follow the document like in a native
   page. Switch off with ?docscroll=0 in the address (kept in localStorage "seppo-doc-scroll"), back on with ?docscroll=1; header.js sets html.no-doc-scroll. Covers the shell pane (tool pages) and the chat page (log, sticky composer). Notes: docs/project/app-shell.md. */
@media (max-width: 480px) {
  /* overflow-x stays clipped: the frost layers stick out sideways, and a phone would widen its layout viewport (and shrink the page) for them */
  html:not(.no-doc-scroll), html:not(.no-doc-scroll) body { overflow: visible; overflow-x: clip; height: auto; min-height: 100dvh; }
  html:not(.no-doc-scroll) body { position: static; inset: auto; width: auto; }
  html:not(.no-doc-scroll).kb-open body { top: auto; height: auto; }
  html:not(.no-doc-scroll) .shell-pane { flex: 1 0 auto; overflow: visible; }
  html:not(.no-doc-scroll) .shell-pane > .shell-scroll { flex: 1 0 auto; overflow: visible; }
  /* The page now scrolls under the floating header: it gets a denser veil so text does not show through it */
  html:not(.no-doc-scroll) :is(.seppo-tool-head, [data-seppo-bar="app"] #main > header) { background: var(--sheen), color-mix(in srgb, var(--sky, #0b1233) 82%, transparent); }
  /* By day the interface ink is dark, so the veil is light too (the dark sky veil left the tool name dark on dark, 1.3:1) */
  html:not(.no-doc-scroll)[data-time="day"]:not([data-scene="workspace"]) :is(.seppo-tool-head, [data-seppo-bar="app"] #main > header) { background: var(--sheen), rgb(252 249 242 / .84); }
  html:not(.no-doc-scroll) [data-scrollspy-root] [id] { scroll-margin-top: calc(80px + var(--safe-top, 0px)); }
  /* Chat: the conversation grows with its messages, the composer sticks to the bottom (above the bottom bar) */
  html:not(.no-doc-scroll) #log-pane { flex: 1 0 auto; overflow: visible; }
  html:not(.no-doc-scroll) #log { flex: 1 0 auto; overflow: visible; }
  /* The sticky offset equals where the composer rests at the end of the page (chat.css margin, ui.css body padding), so it never jumps */
  html:not(.no-doc-scroll) #composer { position: sticky; z-index: 30; bottom: calc(8px + var(--safe-bottom, 0px)); }
  html:not(.no-doc-scroll).has-tabbar #composer { bottom: calc(var(--tabbar-space, 0px) + 16px + var(--safe-bottom, 0px)); }
  html:not(.no-doc-scroll).kb-open #composer { bottom: 8px; }
  /* Keyboard up: the sticky composer is anchored to the layout viewport, so it is lifted by what the keyboard covers */
  html:not(.no-doc-scroll).kb-open #composer { translate: 0 calc(-1 * var(--kb, 0px)); }
}
