/* ============================================================
   shell.css — the application shell: sidebar + topbar + breadcrumb.
   Built entirely from tokens.css. Injected by shell.js; a page only
   needs a #shell-content wrapper around its real markup.
   ============================================================ */

/* Smooth cross-document transitions (dashboard <-> eval/chat pages,
   logo click back to dashboard, etc). Native browser feature - the
   browser snapshots the outgoing page and animates into the incoming
   one instead of tearing down and repainting from blank. Silently
   ignored in browsers that don't support it yet, so this is a pure
   enhancement with no fallback code needed. */
@view-transition {
  navigation: auto;
}

/* The default is a true cross-fade: the outgoing snapshot drops to 0
   while the incoming one rises from 0. Halfway through, BOTH are
   semi-transparent, so the page background shows through both and the
   whole frame washes out - with a near-black sidebar against a white
   backdrop that momentary lightening is exactly what reads as a page
   refresh. Holding the old snapshot fully opaque and fading the new one
   in above it keeps every pixel covered for the whole transition. */
::view-transition-old(root) { animation: none; opacity: 1; }
::view-transition-new(root) { animation: ccg-vt-in 240ms var(--ease-standard, cubic-bezier(.4,0,.2,1)) both; }
@keyframes ccg-vt-in { from { opacity: 0; } to { opacity: 1; } }

/* The sidebar and topbar are identical on both sides of an in-app
   navigation, so they are lifted out of the page snapshot and simply
   stay put rather than being re-drawn. Only the content area moves. */
.shell-sidebar { view-transition-name: ccg-sidebar; }
.shell-topbar  { view-transition-name: ccg-topbar; }
::view-transition-group(ccg-sidebar),
::view-transition-group(ccg-topbar) { animation: none; }
::view-transition-old(ccg-sidebar),
::view-transition-old(ccg-topbar) { animation: none; opacity: 0; }
::view-transition-new(ccg-sidebar),
::view-transition-new(ccg-topbar) { animation: none; opacity: 1; }

@media (prefers-reduced-motion: reduce) {
  @view-transition { navigation: none; }
}

html, body { height: 100%; }
body { overflow-x: clip; overflow-y: visible; }

.shell-frame { display: flex; min-height: 100vh; background: var(--bg-app); }

/* ---------------------------------------------------------------
   Sidebar
--------------------------------------------------------------- */
.shell-sidebar {
  width: 260px; flex-shrink: 0; background: var(--sidebar-bg);
  box-shadow: inset -1px 0 0 var(--sidebar-border);
  display: flex; flex-direction: column;
  position: fixed; left: 0; top: 0; height: 100vh; overflow: hidden;
  transition: width var(--duration-layout) var(--ease-standard),
              transform var(--duration-layout) var(--ease-standard);
  z-index: 40;
}
.shell-sidebar-top { height: var(--topbar-h); flex-shrink: 0; display: flex; align-items: center; padding: 0 var(--sp-5) 0 22px; border-bottom: none; }
/* Wordmark in the display serif, next to the app icon (favicon.svg - the
   white brain on the dark rounded square, the same file the browser tab
   uses). */
.shell-brand { display: flex; align-items: center; gap: 10px; text-decoration: none; color: var(--sidebar-text-active); font-family: var(--font-serif); font-weight: 400; font-size: 23px; letter-spacing: -.02em; white-space: nowrap; overflow: hidden; }
.shell-brand-mark { width: 28px; height: 28px; flex-shrink: 0; border-radius: 7px; display: block; }

/* The nav list is the ONLY scrollable region inside the sidebar - top
   brand and bottom badge stay pinned. */
.shell-nav {
  flex: 1; padding: var(--sp-4) var(--sp-3); overflow-y: auto;
  scrollbar-width: thin; scrollbar-color: var(--sidebar-border) transparent;
}
.shell-nav::-webkit-scrollbar { width: 6px; }
.shell-nav::-webkit-scrollbar-track { background: transparent; }
.shell-nav::-webkit-scrollbar-thumb { background: var(--sidebar-border); border-radius: 3px; }
.shell-nav-group { margin-bottom: var(--sp-6); }
.shell-nav-eyebrow {
  font-size: var(--text-eyebrow-size); font-weight: var(--text-eyebrow-weight);
  letter-spacing: 0; text-transform: none; font-size: var(--text-xs);
  color: var(--sidebar-eyebrow); padding: 0 var(--sp-4); margin-bottom: var(--sp-2);
  white-space: nowrap; overflow: hidden;
  /* .34 gave 3.11:1 on the sidebar, short of AA for 12px; .5 gives 5.29:1. */
}
.shell-nav-item {
  display: flex; align-items: center; gap: 12px; padding: 9px var(--sp-4);
  border-radius: var(--radius-pill); color: var(--sidebar-text); text-decoration: none;
  font-size: 14px; font-weight: 450; cursor: pointer; position: relative;
  border-left: none; margin-bottom: 2px;
  transition: background var(--duration-hover) var(--ease-standard), color var(--duration-hover) var(--ease-standard);
  white-space: nowrap; overflow: hidden;
}
.shell-nav-item:hover { background: var(--sidebar-bg-hover); color: var(--sidebar-text-active); }
.shell-nav-item.active { background: var(--sidebar-bg-active); color: var(--sidebar-text-active); font-weight: 500; box-shadow: var(--shadow-xs); }
/* Accent marker as a pseudo-element rather than a border, so the item's
   own padding and pill shape stay symmetrical - a 3px border-left made
   the active row sit 3px narrower than its neighbours. */
.shell-nav-item.active::before {
  content: ""; position: absolute; left: 0; top: 50%; transform: translateY(-50%);
  width: 3px; height: 18px; border-radius: 0 3px 3px 0; background: var(--accent); display: none;
}
.shell-nav-icon { width: 18px; height: 18px; flex-shrink: 0; display: flex; align-items: center; justify-content: center; }
.shell-nav-label { overflow: hidden; text-overflow: ellipsis; }
.shell-nav-expandable { justify-content: space-between; }
.shell-nav-chevron { width: 14px; height: 14px; flex-shrink: 0; transition: transform var(--duration-hover); margin-left: auto; }
.shell-nav-expandable:has(+ .shell-case-list.open) .shell-nav-chevron { transform: rotate(180deg); }

.shell-case-list { max-height: 0; overflow: hidden; transition: max-height var(--duration-layout) var(--ease-standard); }
.shell-case-list.open { max-height: 240px; }
.shell-case-row {
  display: flex; align-items: center; gap: 12px; padding: 8px var(--sp-3) 8px calc(var(--sp-3) + 18px + 12px);
  color: var(--sidebar-text); text-decoration: none; font-size: 13.5px;
  border-radius: var(--radius-pill); white-space: nowrap; overflow: hidden;
}
.shell-case-row:hover { background: var(--sidebar-bg-hover); color: var(--sidebar-text-active); }
.shell-case-row.active { color: var(--sidebar-text-active); font-weight: 500; }
.shell-case-dot { width: 7px; height: 7px; border-radius: 50%; flex-shrink: 0; }
.shell-case-dot.domain-psychosis { background: var(--domain-psychosis); }
.shell-case-dot.domain-mood { background: var(--domain-mood); }
.shell-case-dot.domain-anxiety { background: var(--domain-anxiety); }
.shell-case-dot.domain-substance { background: var(--domain-substance); }

.shell-sidebar-bottom { flex-shrink: 0; padding: var(--sp-5); border-top: 1px solid var(--sidebar-border); display: flex; align-items: center; gap: var(--sp-3); }
.shell-term-badge { flex: 1; min-width: 0; }
.shell-term-badge-text strong { color: var(--sidebar-text-active); font-weight: 500; }
.shell-term-badge-text { display: block; font-size: 11px; color: var(--sidebar-text); margin-bottom: 6px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.shell-term-badge .progress-track { background: var(--mist-strong); }
.shell-term-badge .progress-fill { background: var(--accent); }

/* ---- Collapsed (desktop only) ---- */
.shell-collapsed .shell-sidebar { width: 68px; }
.shell-collapsed .shell-brand-word,
.shell-collapsed .shell-nav-eyebrow,
.shell-collapsed .shell-nav-label,
.shell-collapsed .shell-nav-chevron,
.shell-collapsed .shell-case-list,
.shell-collapsed .shell-term-badge-text,
.shell-collapsed .shell-term-badge .progress-track { display: none; }
.shell-collapsed .shell-nav-item { justify-content: center; padding: 9px; }
/* The expanded header pads 22px left and 20px right, which leaves 26px for a
   28px icon in the 68px rail - the right edge of the logo was being clipped.
   In the rail the icon is simply centred. */
.shell-collapsed .shell-sidebar-top { padding: 0; justify-content: center; }
.shell-collapsed .shell-brand { gap: 0; overflow: visible; }
.shell-collapsed .shell-case-list.open { max-height: 0; }
.shell-collapsed .shell-nav-item { position: relative; }
.shell-collapsed .shell-nav-item:hover::after {
  content: attr(data-tooltip); position: absolute; left: calc(100% + 10px); top: 50%; transform: translateY(-50%);
  background: var(--text-primary); color: var(--bg-surface); font-size: 12px; font-weight: 500;
  padding: 5px 10px; border-radius: var(--radius-sm); white-space: nowrap; z-index: 100; pointer-events: none;
}

/* ---------------------------------------------------------------
   Topbar
--------------------------------------------------------------- */
.shell-main {
  flex: 1; min-width: 0; display: flex; flex-direction: column;
  margin-left: 260px;
  transition: margin-left var(--duration-layout) var(--ease-standard);
}
.shell-collapsed .shell-main { margin-left: 68px; }
.shell-topbar {
  /* Fixed rather than min-height: the boot layout in this file has to
     reserve this exact height before any of it exists, and a height that
     drifts with the fluid title size cannot be reserved. 72px is the
     tightest the two-line stack fits at the top of the fluid type scale.

     Separation from the page is a single hairline drawn as an inset
     shadow, plus a translucent ground with a blur behind it. A solid
     fill would read as a second surface competing with the cards; this
     way the bar stays part of the page and content passing underneath
     stays visible but muted, which is also what stops the scroll from
     looking like it is disappearing into nothing. */
  height: var(--topbar-h); flex-shrink: 0; position: sticky; top: 0; z-index: 30;
  background: color-mix(in srgb, var(--bg-app) 86%, transparent);
  -webkit-backdrop-filter: blur(16px) saturate(140%); backdrop-filter: blur(16px) saturate(140%);
  box-shadow: inset 0 -1px 0 var(--hairline);
  display: flex; align-items: center; gap: var(--sp-4); padding: 0 var(--sp-7);
}
.shell-hamburger {
  width: 36px; height: 36px; border-radius: 50%; border: none; background: transparent;
  color: var(--text-secondary); display: flex; align-items: center; justify-content: center; cursor: pointer; flex-shrink: 0;
}
.shell-hamburger:hover { background: var(--bg-surface-alt); color: var(--text-primary); }
/* Two-line topbar: the trail sits small and muted above, the page's own
   name sits below it at heading weight. A single-line breadcrumb left
   every page without an actual title in the chrome. */
.shell-topbar-main { min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.shell-breadcrumb { display: flex; align-items: center; gap: 6px; font-size: var(--text-xs); overflow: hidden; white-space: nowrap; }
.shell-topbar-title {
  /* Reset the margin: this element is promoted to an <h1> when the page
     has not declared one of its own, and the browser's default h1 margin
     (0.67em top and bottom, ~29px here) was silently inflating the bar
     and clipping the title on the pages where promotion happens. */
  margin: 0;
  font-family: var(--font-serif); font-size: clamp(1.25rem, 1.15rem + .4vw, 1.5rem); font-weight: 400; letter-spacing: -.015em;
  color: var(--text-primary); line-height: 1.2;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
@media (max-width: 767px) {
  /* Keep only the immediate parent above the title - the full trail does
     not fit, and the title already says where you are. */
  .shell-crumb:not(:nth-last-child(3)), .shell-crumb-sep { display: none; }
  .shell-breadcrumb { font-size: var(--text-xs); }
}
.shell-crumb { color: var(--text-secondary); text-decoration: none; }
.shell-crumb:hover { color: var(--text-primary); }
.shell-crumb.current { color: var(--text-tertiary); font-weight: 400; }
.shell-crumb-sep { color: var(--text-tertiary); }
.shell-topbar-right { margin-left: auto; display: flex; align-items: center; gap: var(--sp-2); flex-shrink: 0; }

.shell-body { flex: 1; }
/* The column cap is a variable so the boot layout in this file can reserve
   the same width. Pages that want a wider column (the evaluation pages
   use 1900px for their two-column grid) set --shell-content-max on :root
   rather than overriding this rule, which would leave the boot layout
   reserving a column of the wrong width. */
.shell-content-inner { max-width: var(--shell-content-max, 1200px); margin: 0 auto; padding: var(--sp-8) clamp(24px, 16px + 2vw, 48px) var(--sp-9); }

/* ---------------------------------------------------------------
   Mobile backdrop (drawer overlay)
--------------------------------------------------------------- */
.shell-backdrop { display: none; position: fixed; inset: 0; background: rgba(20,20,19,.32); -webkit-backdrop-filter: blur(2px); backdrop-filter: blur(2px); z-index: 39; opacity: 0; transition: opacity var(--duration-layout); }
.shell-backdrop.open { display: block; opacity: 1; }

/* ---------------------------------------------------------------
   Responsive
--------------------------------------------------------------- */
@media (max-width: 1023px) {
  .shell-sidebar {
    position: fixed; left: 0; top: 0; transform: translateX(-100%);
    box-shadow: var(--shadow-lg);
  }
  .shell-sidebar.open { transform: translateX(0); }
  .shell-collapsed .shell-sidebar { width: 260px; } /* collapse is desktop-only; mobile always uses the drawer at full width */
  .shell-collapsed .shell-brand-word, .shell-collapsed .shell-nav-eyebrow, .shell-collapsed .shell-nav-label,
  .shell-collapsed .shell-nav-chevron, .shell-collapsed .shell-term-badge-text, .shell-collapsed .shell-term-badge .progress-track { display: revert; }
  .shell-collapsed .shell-nav-item { justify-content: flex-start; padding: 9px var(--sp-3); }
  .shell-collapsed .shell-sidebar-top { padding: 0 var(--sp-5) 0 22px; justify-content: flex-start; }
  .shell-collapsed .shell-brand { gap: 10px; }
  .shell-content-inner { padding: var(--sp-5) var(--sp-4) var(--sp-7); }
  .shell-topbar { padding: 0 var(--sp-4); height: var(--topbar-h); }
  .shell-main, .shell-collapsed .shell-main { margin-left: 0; }
}

@media (prefers-reduced-motion: reduce) {
  .shell-sidebar, .shell-nav-item, .shell-case-list, .shell-backdrop { transition: none; }
}

/* ===============================================================
   Boot layout — first paint, before shell.js runs
   ---------------------------------------------------------------
   shell.js assembles the sidebar, topbar and frame in JavaScript
   at the bottom of the document. Until it executes, the page has
   no chrome at all: content paints at the full viewport width
   starting at x=0, and then shifts right by the sidebar width and
   reflows once the script lands. On a warm cache that is a frame
   or two; on a cold one it is the "the sidebar loads late" jump.

   These rules paint the sidebar band and reserve the content's
   final geometry from the very first frame, using the state that
   theme-init.js resolved in <head>. They are switched off the
   moment shell.js adds .shell-ready, handing over to the real
   chrome with nothing to move.
=============================================================== */
html:not(.shell-ready) body { background: var(--bg-app); }

/* The dark band. Painted by the document itself so it exists in the
   first frame, then replaced by the real sidebar. */
html:not(.shell-ready) body::before {
  content: ""; position: fixed; left: 0; top: 0; height: 100vh;
  width: 260px; background: var(--sidebar-bg); z-index: 40;
}
html[data-shell-sidebar="collapsed"]:not(.shell-ready) body::before { width: 68px; }
html[data-shell-sidebar="drawer"]:not(.shell-ready) body::before { display: none; }

/* Reserve the content's final box. The left offset reproduces what the
   assembled shell produces: the sidebar's width, then the inner column
   centred within whatever space is left, capped at 1200px. Below that
   cap the centring term is zero, so on ordinary laptop widths this is
   simply sidebar + gutter. */
html:not(.shell-ready) #shell-content {
  --boot-sidebar: 260px;
  --boot-gutter: var(--sp-7);
  box-sizing: border-box;
  display: block;
  margin: 0;
  padding-top: calc(var(--topbar-h) + var(--sp-7));
  padding-bottom: var(--sp-8);
  /* The centring term has to appear on BOTH sides. With it only on the
     left, the content box stays wider than the real 1200px column, and
     anything that centres itself inside (the evaluation pages' grid)
     lands in a different place before and after the handover. */
  padding-right: calc(
    var(--boot-gutter) +
    max(0px, (100vw - var(--boot-sidebar) - var(--shell-content-max, 1200px)) / 2)
  );
  padding-left: calc(
    var(--boot-sidebar) + var(--boot-gutter) +
    max(0px, (100vw - var(--boot-sidebar) - var(--shell-content-max, 1200px)) / 2)
  );
}
html[data-shell-sidebar="collapsed"]:not(.shell-ready) #shell-content { --boot-sidebar: 68px; }
html[data-shell-sidebar="drawer"]:not(.shell-ready) #shell-content { --boot-sidebar: 0px; }

/* 1023px, not 767px: the shell's own mobile padding and topbar height
   live in the max-width:1023px block, and the boot layout has to switch
   at exactly the same width or the two disagree in the 768-1023 band. */
@media (max-width: 1023px) {
  html:not(.shell-ready) #shell-content {
    --boot-gutter: var(--sp-4);
    padding-top: calc(var(--topbar-h) + var(--sp-5));
    padding-bottom: var(--sp-7);
  }
}

/* Suppress the sidebar's width transition on the very first frame, or the
   handover from the boot band to the real sidebar animates from 0. */
html:not(.shell-ready) .shell-sidebar,
html:not(.shell-ready) .shell-main { transition: none !important; }

/* Global disclaimer, rendered by shell.js under every page's content. */
.shell-footer {
  max-width: var(--shell-content-max, 1100px);
  margin: var(--sp-8) auto 0;
  padding: var(--sp-5) var(--sp-5) calc(var(--sp-6) + env(safe-area-inset-bottom, 0px));
  font-size: var(--text-xs);
  color: var(--text-tertiary);
  text-align: center;
  box-shadow: inset 0 1px 0 var(--border);
}
.shell-footer a { color: var(--text-secondary); font-weight: 500; text-decoration: none; }
.shell-footer a:hover { text-decoration: underline; text-underline-offset: 3px; }

/* ---------------------------------------------------------------
   Nav icons (alpha r9): glyphs only, no circles, all in the one accent
   of the palette - sienna in the light theme, peach in the dark. The
   three-colour version (sienna / brass / steel, plus the case colour on
   the Cases glyph) read as mismatched rather than as sections. The active
   item's glyph is ink, like its label.
--------------------------------------------------------------- */
.shell-nav-group .shell-nav-icon,
#shell-cases-toggle .shell-nav-icon { color: var(--accent); }
.shell-nav .shell-nav-item.active .shell-nav-icon { color: var(--text-primary); }
