/* semgit — the shell's stylesheet, cut into files along its sections (#70,
   docs/ui-pass.md §4) so each lane owns one. base.html links them in this
   order, which is the order the sections had in the one file:
     tokens · topbar · desk · sheet · notes · edit · home
   tokens.css: the tokens, the scheme, the reset, the buttons, the states
   the frame owns, the print base and reduced motion. */

/* semgit — layer 1: shell.

   Press: near-monochrome grotesk, hairline rules, tight tracking. Colour is
   held back almost entirely so it still means something when the semantic layer
   finally spends it.

   Dark mode is section 2: the same ramp inverted, honouring the OS and
   overridable with [data-theme] on <html>.

   Fonts are OS stacks, so nothing is downloaded and nothing is pinned. If Inter
   proper is wanted over the Segoe/system fallback it gets self-hosted as woff2
   in this directory — no CDN, no build step — and a DECISIONS.md entry, per the
   house rule on new dependencies. */

/* ---------------------------------------------------------------- 1. tokens */

:root {
  /* Both, so light-dark() below can resolve either way and the OS decides
     by default. [data-theme] on <html> forces one. */
  color-scheme: light dark;

  /* Neutrals. A warm grey ramp — the same lightnesses as a neutral one with the
     hue pushed off cold, so the desk reads as paper stock rather than a screen.
     --ink..--ink-3 carry text and each clears 4.5:1 on --surface in BOTH
     schemes; --line and --line-2 are hairlines only.

     light-dark() carries both values in one declaration. The previous version
     wrote the dark ramp out twice — once under prefers-color-scheme, once under
     [data-theme="dark"] — and the two promptly disagreed the first time the
     palette was edited: the media block was warmed and the attribute block was
     left cold. One declaration cannot drift from itself. */
  --ink:         light-dark(#14130f, #ebe9e4);
  --ink-2:       light-dark(#474440, #b8b4ad);
  --ink-3:       light-dark(#75706a, #8b867f);
  --line:        light-dark(#e0ddd7, #302e2a);
  --line-2:      light-dark(#efedea, #24221f);
  --surface:     light-dark(#fffefc, #1a1917);
  --canvas:      light-dark(#f7f5f1, #111110);
  /* The desk's grid (ui-pass lane 2): cell size and the line, faint on both grounds. */
  --grid: 24px;
  --grid-line: light-dark(rgba(20, 19, 15, .055), rgba(236, 235, 230, .05));
  --sunken:      light-dark(#f0eee9, #262420);

  /* "Accent" is near-black on purpose: action reads as weight, not hue. Dark
     inverts that to near-white; nothing gains a colour it did not have. */
  --accent:      light-dark(#14130f, #ebe9e4);
  --accent-2:    light-dark(#000000, #ffffff);
  --accent-ink:  light-dark(#fffefc, #14130f);
  --accent-wash: light-dark(#efedea, #2a2823);

  --danger:      light-dark(#b3261e, #ef8a84);
  --danger-wash: light-dark(#fdeceb, #3a2220);
  --ok:          light-dark(#2e7d5b, #5cbb8b);
  --ok-wash:     light-dark(#e9f4ee, #1f3128);
  --warn:        light-dark(#b7791f, #e2b25c);
  --warn-wash:   light-dark(#fbf2df, #3a2f18);
  /* The product's semantics as colour (docs/UI-BRIEF.md 2.1): what a change did,
     and what blocks. They mean the same thing on every surface; --blocked is
     for nothing that is not blocked. Light is a second mapping of the same names. */
  --meaning:     light-dark(#b7791f, #e0a15a);
  --wording:     light-dark(#2e7d5b, #7fa88a);
  --blocked:     light-dark(#b3261e, #d16a5f);
  --focus:       light-dark(#3565c9, #8fb0d8);

  /* Space — 4pt scale, and the shell uses the small end of it. */
  --s1: 4px;  --s2: 6px;  --s3: 10px; --s4: 14px;
  --s5: 20px; --s6: 28px; --s7: 40px; --s8: 56px;

  --r1: 2px; --r2: 3px; --r3: 5px;

  /* Two heights: sitting on the desk, and floating over it. */
  --e1: 0 1px 2px rgba(16, 18, 21, .05);
  --e2: 0 1px 2px rgba(16, 18, 21, .06), 0 4px 12px rgba(16, 18, 21, .05);
  /* A card lifted off the desk (ui-pass): the paper, the history card, a note. */
  --e3: 0 1px 2px rgba(16, 18, 21, .05), 0 6px 18px rgba(16, 18, 21, .07);

  --ease: cubic-bezier(.2, .6, .3, 1);
  --fast: 90ms; --mid: 160ms;

  --topbar-h: 40px;

  /* The dock's height, so the history panel can start level with the paper
     rather than level with the dock floating above it. */
  --dock-h: 38px;
  --ribbon-h: 38px;   /* the Edit mode's formatting bar (#68) */

  /* The panel's fold button, and the size of the square the panel clips down to.
     It also sets the panel's text gutter: the header label and every commit
     title start at --handle, so the two columns line up by arithmetic rather
     than by two hand-tuned paddings drifting apart. */
  --handle: 32px;

  /* The panel is a fixed size, like the sheet is. Deriving it from whatever
     margin the paper left over meant it was a different width on every window
     and never looked settled. The window accommodates it; below --flow-at the
     window cannot, and the panel joins the flow and pushes the paper instead.
     --flow-at = --sheet-w + 2 * (--rail-w + --s4 + --channel)
               = 794 + 2 * (240 + 14 + 16) = 1334px.
     Media queries cannot read custom properties, so that literal is in the
     @media below and this is the arithmetic behind it. CHANGE --rail-w AND YOU
     MUST MOVE THAT NUMBER: every 100px on the panel is 200px on the
     breakpoint. */
  --rail-w: 185px;   /* the history card (ui-pass lane 2); the submissions column too */
  --channel: 16px;

  /* Annotations in the right margin. Not a panel — each card floats beside the
     sentence it is about, the way a margin note does. */
  --note-w: 260px;
  --note-gap: 8px;

  /* THE PAGE IS A PAGE. A4 width, written in millimetres so it is not a number
     anybody is tempted to tune: the browser resolves 210mm to 793.7px, and the
     same value drives the PDF (SPEC G.5, CSS Paged Media).

     INVARIANT: the sheet's dimensions never change. Not for a panel, not for
     the annotation gutter, not for the window. A manuscript whose line breaks
     move when you open a sidebar is not a manuscript. Everything else yields
     first — the annotations give up their column, then the desk scrolls. */
  --sheet-w: 210mm;
  --spread-w: 1080px;

  --t-xs: 11px; --t-sm: 12px; --t-md: 13px; --t-lg: 15px; --t-xl: 19px;
  --ui-tracking: -.006em;
  --rail-weight: 500;

  --ui:    "Inter", "Inter Tight", "Segoe UI Variable Text", "Segoe UI",
           ui-sans-serif, system-ui, -apple-system, "Helvetica Neue", sans-serif;
  /* The user's prose is a serif; the interface is the grotesque above
     (docs/UI-BRIEF.md 2.2). A system stack: nothing is fetched to read a page. */
  --prose: "Charter", "Iowan Old Style", "Source Serif Pro", "Source Serif 4", Georgia,
           "Times New Roman", serif;
  --mono:  "Cascadia Mono", ui-monospace, Consolas, "SF Mono", monospace;
}

/* ----------------------------------------------------------- 2. scheme ---

   The palette itself is in the tokens above. Only two things are left here:
   the explicit override, and the shadows — light-dark() is a colour function
   and a box-shadow is not a colour. */

:root[data-theme="light"] { color-scheme: light; }
:root[data-theme="dark"]  { color-scheme: dark; }

/* Shadow does little on a dark ground; there, the borders carry separation. */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --e1: 0 1px 2px rgba(0, 0, 0, .5);
    --e2: 0 1px 3px rgba(0, 0, 0, .6), 0 6px 18px rgba(0, 0, 0, .45);
    --e3: 0 1px 3px rgba(0, 0, 0, .55), 0 8px 24px rgba(0, 0, 0, .4);
  }
}
:root[data-theme="dark"] {
  --e1: 0 1px 2px rgba(0, 0, 0, .5);
  --e2: 0 1px 3px rgba(0, 0, 0, .6), 0 6px 18px rgba(0, 0, 0, .45);
  --e3: 0 1px 3px rgba(0, 0, 0, .55), 0 8px 24px rgba(0, 0, 0, .4);
}

/* ----------------------------------------------------------------- 3. reset */

*, *::before, *::after { box-sizing: border-box; }

html, body { height: 100%; }

body {
  margin: 0;
  font: var(--t-md)/1.5 var(--ui);
  letter-spacing: var(--ui-tracking);
  color: var(--ink);
  background: var(--canvas);
  -webkit-font-smoothing: antialiased;
}

h1, h2, h3, h4, p, figure { margin: 0; }

a { color: var(--accent); text-decoration: none; }
a:hover { text-decoration: underline; }

button, input, select, textarea { font: inherit; color: inherit; letter-spacing: inherit; }
[hidden] { display: none !important; }

:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; border-radius: var(--r1); }
:focus:not(:focus-visible) { outline: none; }

.sr-only {
  position: absolute; width: 1px; height: 1px; overflow: hidden;
  clip-path: inset(50%); white-space: nowrap;
}

.mono { font-family: var(--mono); font-size: .93em; }
.prose { font-family: var(--prose); }

/* From section 4. It sits here, ahead of section 8's .empty, because that
   rule overrides this one and the cascade must not turn around. */
/* The page a fresh repo shows: the desk, the paper, one thing to do on it. */
.empty { display: grid; gap: var(--s4); justify-items: start; padding: var(--s6) 0; }
.empty h1 { font-family: var(--prose); font-size: 22px; font-weight: 600; }
.empty p { color: var(--ink-2); }

/* ----------------------------------------------------------------- 7. buttons */

.btn {
  display: inline-flex; align-items: center; gap: var(--s2);
  padding: var(--s1) var(--s3);
  min-height: 26px;
  border: 1px solid var(--line);
  border-radius: var(--r2);
  background: var(--surface);
  color: var(--ink-2);
  font-family: var(--ui);
  font-size: var(--t-sm); font-weight: 500;
  cursor: pointer; white-space: nowrap;
  transition: background var(--fast) var(--ease), border-color var(--fast) var(--ease),
              color var(--fast) var(--ease);
}
.btn:hover { background: var(--sunken); color: var(--ink); text-decoration: none; }

.btn.primary { background: var(--accent); border-color: var(--accent); color: var(--accent-ink); }
.btn.primary:hover { background: var(--accent-2); border-color: var(--accent-2); color: var(--accent-ink); }

.btn.ghost { background: transparent; border-color: transparent; }
.btn.ghost:hover { background: var(--sunken); }

.btn[disabled], .btn[aria-disabled="true"] { opacity: .45; cursor: not-allowed; }

.inline { display: inline; }

/* ------------------------------------------------- 8. states the frame owns */

.loading {
  position: fixed; inset: 0 0 auto; height: 2px;
  background: var(--accent); transform-origin: 0 50%;
  animation: loadbar 1.1s var(--ease) infinite; z-index: 9;
}
@keyframes loadbar {
  0%   { transform: scaleX(0);   opacity: 1; }
  60%  { transform: scaleX(.85); opacity: 1; }
  100% { transform: scaleX(1);   opacity: 0; }
}
[aria-busy="true"] { cursor: progress; }

.error {
  padding: var(--s2) var(--s3);
  border: 1px solid var(--danger);
  border-radius: var(--r2);
  background: var(--danger-wash);
  color: var(--danger);
  font-size: var(--t-sm);
}

/* An empty state always carries the way out (SPEC G.4). */
.empty {
  display: grid; justify-items: center; gap: var(--s3);
  max-width: 380px; margin: var(--s7) auto;
  padding: var(--s5) var(--s4);
  border: 1px solid var(--line);
  border-radius: var(--r3);
  background: var(--surface);
  text-align: center;
}
.empty h2 { font-family: var(--prose); font-size: var(--t-lg); font-weight: 600; }
.empty p { font-size: var(--t-sm); color: var(--ink-3); }


/* ------------------------------------------------------------- print ---

   Ctrl+P gives the manuscript and only the manuscript — Clean reading, on
   paper. The desk, the chrome, the discussion and its markers all stay on the
   screen. (The PDF export is a different path: render.py and print.css, §G.5,
   which owns page numbers and running heads. This is just the browser.) */
@media print {
  @page { size: A4; margin: 0; }
  .topbar, .busy, .rail, .rail-toggle, .dock, .margin, .gutter, .marks,
  .selbar, .toasts, .skip, .pagefoot { display: none !important; }
}

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 1ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 1ms !important;
  }
}
