/* fraction-ds — dist/css/shell.css
   The app frame: the parts of a product that are the same on every screen.
   NEW in the system (Canvas had no left rail and built its frame out of
   Tailwind utilities), so every rule here is written against the existing
   laws rather than invented:
     · the only colours are tokens,
     · regions are separated by a 1px --line hairline, never by a tint or
       a card shadow (Common Region),
     · radii are 6 / 8 / 12; the big regions (rail, header, bar, main) are
       square, exactly like .panel,
     · nothing animates for longer than 120ms (Doherty),
     · type is 15 / 13 / 11 — nothing smaller, nothing in between.

   .hdr and .bar themselves are defined in ds.css (they came from Canvas);
   this file only places them in the grid. .empty likewise lives in ds.css;
   shell only centres it inside .main. */

/* ── .shell — the whole window ────────────────────────────────────
   Three columns (rail / main / drawer), three rows (header / body / bar).
   The grid, not a stack of absolutely positioned boxes, so a rail or a
   drawer can be collapsed by changing one track to 0 and nothing else
   has to move. min-height: 0 on the body row is what stops a tall rail
   from pushing the bar off the bottom of the screen. */
.shell {
  display: grid;
  grid-template-columns: auto 1fr auto;
  grid-template-rows: auto minmax(0, 1fr) auto;
  grid-template-areas:
    "hdr    hdr    hdr"
    "rail   main   drawer"
    "bar    bar    bar";
  height: 100vh;
  height: 100dvh;
  overflow: hidden;
  background: var(--bg);
}
.shell > .hdr { grid-area: hdr; }
.shell > .bar { grid-area: bar; }
.shell > .rail { grid-area: rail; }
.shell > .main { grid-area: main; }
.shell > .drawer { grid-area: drawer; }

/* A shell without a rail, a bar or a drawer simply omits the element —
   `auto` tracks collapse to zero when nothing occupies them. */

/* ── .shell--rail-full — the rail runs top to bottom ──────────────
   For a product whose brand and search live at the head of its rail
   (Notes) instead of in a header across the whole window. The rail owns
   the left column from the top edge to the bottom one; the header, main,
   drawer and bar share the rest. .rail__head is --h-bar tall, exactly
   like .hdr, so the two bottom hairlines meet in one straight line.
   Below 860 the responsive block further down takes over unchanged. */
.shell--rail-full {
  grid-template-areas:
    "rail   hdr    hdr"
    "rail   main   drawer"
    "rail   bar    bar";
}

/* ── .pagehead — what this page is ────────────────────────────────
   One band directly under .hdr, at most one per page: the page's h1 and
   one sentence saying what the page does. It is the only h1 on the
   screen, so it is a landmark, not decoration — which is why it stays
   on the type scale (15 for the title, 13 for the sentence) and earns
   its separation from a hairline rather than a size jump. Title and
   sentence sit on one baseline and wrap to two lines under 720, where
   a sentence next to a title would leave the title two words wide. */
.pagehead {
  display: flex;
  align-items: baseline;
  gap: 10px;
  flex: 0 0 auto;
  padding: 10px 16px;
  border-bottom: 1px solid var(--line);
  background: var(--bg);
}
.pagehead__title {
  margin: 0;
  font-size: var(--fs-body);
  font-weight: 600;
  line-height: 1.2;
  letter-spacing: -.01em;
  color: var(--ink);
  white-space: nowrap;
}
.pagehead__desc {
  margin: 0;
  min-width: 0;
  font-size: var(--fs-ui);
  line-height: 1.3;
  color: var(--ink-2);
}
/* Anything the page keeps at its top right — a count, a chip, a button. */
.pagehead__actions {
  margin-left: auto;
  display: flex;
  align-items: center;
  gap: 8px;
}

@media (max-width: 720px) {
  .pagehead { flex-wrap: wrap; gap: 2px 10px; }
  .pagehead__desc { flex: 1 0 100%; }
}

/* ── .main — the one scrolling region ─────────────────────────── */
.main {
  min-width: 0;
  min-height: 0;
  overflow: auto;
  background: var(--bg);
  display: flex;
  flex-direction: column;
}
.main--pad { padding: var(--pad-main); }
.main--center { align-items: center; }
.main > .empty { margin: auto; }

/* ── .rail — the left navigation ──────────────────────────────────
   280px (--w-rail), hairline on its right edge, its own scroll. Holds a
   head, a tree of .rail__row items, and a foot pinned to the bottom. */
.rail {
  width: var(--w-rail);
  flex: none;
  min-height: 0;
  display: flex;
  flex-direction: column;
  background: var(--bg);
  border-right: 1px solid var(--line);
  overflow: hidden;
}
.rail--right { border-right: none; border-left: 1px solid var(--line); }
.rail__head {
  height: var(--h-bar);
  flex: none;
  padding: 0 12px;
  display: flex;
  align-items: center;
  gap: 8px;
  border-bottom: 1px solid var(--line);
}
.rail__body { flex: 1 1 auto; min-height: 0; overflow: auto; padding: 8px; }
.rail__foot {
  flex: none;
  padding: 8px;
  border-top: 1px solid var(--line);
  display: flex;
  align-items: center;
  gap: 8px;
}
/* A section label inside the rail. 11px, quiet — it names a group, it is
   not a row you can click. */
.rail__label {
  font-size: var(--fs-meta);
  color: var(--ink-3);
  padding: 10px 8px 4px;
  display: flex;
  align-items: center;
  gap: 6px;
}
.rail__label .btn { margin-left: auto; }

/* Tree rows. Same shape as ds.css's .row (32px, radius 6, hover --bg-2,
   accent-soft when current) plus the two things a tree needs: a depth
   indent and a disclosure twisty that rotates in 120ms. */
.rail__row {
  min-height: 32px;
  padding: 0 8px;
  border-radius: var(--r-1);
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: var(--fs-ui);
  color: var(--ink-2);
  text-decoration: none;
  cursor: pointer;
  transition: background-color 120ms, color 120ms;
}
.rail__row:hover { background: var(--bg-2); color: var(--ink); }
.rail__row--on { background: var(--accent-soft); color: var(--ink); }
.rail__row--depth-1 { padding-left: 24px; }
.rail__row--depth-2 { padding-left: 40px; }
.rail__row--depth-3 { padding-left: 56px; }
.rail__row__name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.rail__row__meta { margin-left: auto; font-family: var(--mono); font-size: var(--fs-meta); color: var(--ink-3); }
/* The twisty is a chevron-right that turns down when the branch is open;
   the row keeps one icon slot either way, so nothing shifts sideways. */
.rail__twisty {
  width: 16px; height: 16px; flex: none;
  display: flex; align-items: center; justify-content: center;
  color: var(--ink-3);
  transition: transform 120ms;
}
.rail__row--open > .rail__twisty { transform: rotate(90deg); }
.rail__row--leaf > .rail__twisty { visibility: hidden; }

/* ── .drawer — the right slide-over ───────────────────────────────
   Inside the shell grid (not floating over it), so opening one narrows
   the main column instead of hiding it. Slides in 120ms. Products that
   need it over the content on a narrow window flip it to .drawer--over. */
.drawer {
  width: var(--w-drawer);
  max-width: 100vw;
  flex: none;
  min-height: 0;
  display: flex;
  flex-direction: column;
  background: var(--bg);
  border-left: 1px solid var(--line);
  overflow: hidden;
  transition: transform 120ms, opacity 120ms;
}
.drawer[hidden] { display: none; }
.drawer--enter { transform: translateX(8px); opacity: 0; }
.drawer__head {
  height: var(--h-bar);
  flex: none;
  padding: 0 12px;
  display: flex;
  align-items: center;
  gap: 8px;
  border-bottom: 1px solid var(--line);
  font-size: var(--fs-ui);
  font-weight: 600;
}
.drawer__head .btn--icon { margin-left: auto; }
.drawer__body { flex: 1 1 auto; min-height: 0; overflow: auto; padding: 16px; }
.drawer__foot {
  flex: none;
  padding: 12px;
  border-top: 1px solid var(--line);
  display: flex;
  align-items: center;
  gap: 8px;
  justify-content: flex-end;
}
/* Floating variant: same box, pinned to the right edge above the content. */
.drawer--over {
  position: fixed;
  top: 0;
  right: 0;
  bottom: 0;
  z-index: 90;
  box-shadow: var(--shadow-menu);
}

/* ── .card — a movable unit of content (kanban card, note, result) ──
   The one place in the system with a radius on a region, because a card
   is an object you pick up, not a region of the window. Still a hairline,
   still no shadow — the lift on drag is a border colour, not a shadow. */
.card {
  background: var(--bg);
  border: 1px solid var(--line);
  border-radius: var(--r-2);
  padding: 12px;
  display: flex;
  flex-direction: column;
  gap: 8px;
  font-size: var(--fs-ui);
  color: var(--ink);
  text-decoration: none;    /* a card is often a link to the thing it stands for */
  transition: border-color 120ms, background-color 120ms;
}
.card:hover { border-color: var(--line-2); }
.card--on { border-color: var(--accent); background: var(--accent-soft); }
.card--drag { border-color: var(--accent); }
/* Raised: a card sitting on the --board surface (a kanban column) takes
   --bg-2 so it separates from the board without a shadow. */
.card--raised { background: var(--bg-2); }
.card__title { font-size: var(--fs-ui); font-weight: 600; color: var(--ink); margin: 0; }
.card__meta {
  display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
  font-size: var(--fs-meta); color: var(--ink-3);
}
.card__meta .mono, .card__grip { color: var(--ink-3); }
.card__grip { cursor: grab; }
.card__grip:active { cursor: grabbing; }

/* ── .progress — a hairline that fills ────────────────────────────
   4px, square, accent fill on an --ink-4 track. Determinate only; a
   spinner that spins forever is a dot (.dot--accent), not a bar. */
.progress {
  height: 4px;
  width: 100%;
  background: var(--ink-4);
  overflow: hidden;
}
.progress__fill {
  height: 100%;
  width: 0;
  background: var(--accent);
  transition: width 120ms;
}
.progress--ok .progress__fill { background: var(--ok); }
.progress--warn .progress__fill { background: var(--warn); }
.progress--danger .progress__fill { background: var(--danger); }
/* Thin: the quiet 2px form for a bar that repeats down a list (a checklist
   on every kanban card). A --line track and an --ink-2 fill, so twenty of
   them do not turn a column blue; a tone modifier still recolours the fill
   (--ok when the list is complete). */
.progress--thin { height: 2px; background: var(--line); }
.progress--thin .progress__fill { background: var(--ink-2); }
.progress--thin.progress--ok .progress__fill { background: var(--ok); }
.progress--thin.progress--warn .progress__fill { background: var(--warn); }
.progress--thin.progress--danger .progress__fill { background: var(--danger); }
/* The 11px "7 / 12" readout that belongs next to one. */
.progress__label { font-family: var(--mono); font-size: var(--fs-meta); color: var(--ink-3); }

/* ── .skeleton — the shape of content that is on its way ──────────
   A --bg-2 block with the control radius. Lay several out in the rough
   shape of what is coming (a bar, a rail, a heading, three lines) so the
   wait already shows where things will be — never a spinner alone in an
   empty box, and never on a --bg-2 surface, where it would vanish.

   THE ONE LOOP. Every other motion in the system is a <=120ms answer to
   something the person did. A skeleton is the system saying it is still
   working, so its sweep repeats: slowly (1.6s), in --ink-4, and only while
   the content is genuinely on its way — take the skeleton out the moment
   the content lands. `.skeleton--still` is the queued form, no sweep.
   Reduced motion stops the sweep outright (an infinite 1ms loop would
   flicker, so base.css's clamp is not enough here).

   Many skeletons sweep as one wave when they share a phase: a product sets
   --skeleton-sync (a negative delay, e.g. -(now % 1600)ms) on each as it
   mounts, so a board of them does not shimmer like confetti. */
.skeleton {
  display: block;
  position: relative;
  overflow: hidden;
  background: var(--bg-2);
  border-radius: var(--r-1);
}
.skeleton::after {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(90deg, transparent, var(--ink-4), transparent);
  transform: translateX(-100%);
  animation: ds-skeleton-sweep 1.6s linear infinite;
  animation-delay: var(--skeleton-sync, 0ms);
}
@keyframes ds-skeleton-sweep { to { transform: translateX(100%); } }
/* One line of text to come: 8px, the x-height of 13px type. Width is the
   product's to set — vary it, three equal lines read as a table. */
.skeleton--line { height: 8px; }
.skeleton--still::after { content: none; }
@media (prefers-reduced-motion: reduce) {
  .skeleton::after { animation: none; }
}

/* ── .palette — the command palette ───────────────────────────────
   A .menu that opens from the top of the window instead of from a
   button: same shadow, same item shape, one input welded to the top.
   Every row carries its key, because the palette is where people learn
   the keys. */
.palette {
  position: fixed;
  top: 12vh;
  left: 50%;
  transform: translateX(-50%);
  z-index: 130;
  width: min(560px, 92vw);
  max-height: 60vh;
  display: flex;
  flex-direction: column;
  background: var(--bg);
  border: 1px solid var(--line-2);
  border-radius: var(--r-3);
  box-shadow: var(--shadow-menu);
  overflow: hidden;
}
.palette__input {
  height: var(--h-bar);
  flex: none;
  width: 100%;
  padding: 0 14px;
  border: none;
  border-bottom: 1px solid var(--line);
  background: transparent;
  color: var(--ink);
  font-family: var(--sans);
  font-size: var(--fs-body);
}
.palette__input:focus { outline: none; }
.palette__list { flex: 1 1 auto; min-height: 0; overflow: auto; padding: 6px; }
.palette__label { font-size: var(--fs-meta); color: var(--ink-3); padding: 8px 8px 4px; }
.palette__item {
  min-height: var(--h-control);
  padding: 0 8px;
  border-radius: var(--r-1);
  display: flex;
  align-items: center;
  gap: 10px;
  width: 100%;
  border: none;
  background: none;
  text-align: left;
  color: var(--ink);
  font-size: var(--fs-ui);
  cursor: pointer;
}
.palette__item:hover { background: var(--bg-2); }
/* Keyboard cursor, not hover — the palette is driven by arrow keys. */
.palette__item--on { background: var(--accent-soft); }
.palette__item .kbd, .palette__item .kbds { margin-left: auto; }
.palette__hint { font-size: var(--fs-meta); color: var(--ink-3); margin-left: auto; font-family: var(--mono); }
.palette__foot {
  flex: none;
  padding: 8px 12px;
  border-top: 1px solid var(--line);
  display: flex;
  align-items: center;
  gap: 12px;
  font-size: var(--fs-meta);
  color: var(--ink-3);
}

/* ── responsive ───────────────────────────────────────────────────
   One breakpoint, one behaviour: below 860 the rail stops being a column
   and becomes an overlay the product toggles, and the drawer goes full
   width. No second layout to maintain. */
@media (max-width: 860px) {
  .shell {
    grid-template-columns: 1fr;
    grid-template-areas:
      "hdr"
      "main"
      "bar";
  }
  .shell > .rail {
    position: fixed;
    top: var(--h-bar);
    bottom: 0;
    left: 0;
    z-index: 90;
    box-shadow: var(--shadow-menu);
  }
  .shell > .rail[hidden] { display: none; }
  .shell > .drawer { position: fixed; inset: var(--h-bar) 0 0; width: 100%; z-index: 90; }
}
