# ADR: Layout Height Propagation Standard

**Status:** ACCEPTED  
**Date:** 2026-08-16  
**Authors:** Claude Code  

---

## Context

Multi-level frontend layouts (PageLayout → QueryBoundary → content) require explicit height propagation to ensure:
1. **Single-screen principle**: First load fits viewport without scroll
2. **Internal scrolling**: Only nested containers scroll, not the page
3. **Consistent behavior**: All pages follow the same height rules

Previous bugs stemmed from missing `flex: 1; min-height: 0;` constraints at various levels.

---

## Decision

Establish a **required height propagation chain** for all pages:

```
PageLayout (.ks-page__content)
  ├─ height: 100%
  ├─ min-height: 0
  └─ display: flex
     
  ↓ (child must propagate height)
  
QueryStateBoundary (.ks-query-boundary)
  ├─ flex: 1
  ├─ height: 100%
  ├─ min-height: 0
  └─ display: flex
     
  ↓ (child must propagate height)
  
Content Container (grid, splitter, or flex child)
  ├─ flex: 1        (if flex child)
  ├─ height: 100%   (if direct child of flex parent)
  ├─ min-height: 0  (always required for flex children)
  └─ overflow: (auto|hidden)
     
  ↓ (internal scrollable panes)
  
Internal Panes (.items, .detail-panel, etc.)
  ├─ flex: 1
  ├─ min-height: 0
  └─ overflow-y: auto
```

---

## Rationale

1. **Flex layout principle**: Flex children must have `min-height: 0` to respect parent constraints
2. **Height inheritance**: `height: 100%` only works when parent has explicit height
3. **Single responsibility**: Each layer only enforces its own constraints, children handle overflow

---

## Implementation

### For Grid-Based Pages (.ks-stack)

```css
.ks-stack {
  display: grid;
  gap: var(--ks-space-4);
  flex: 1;          /* Required: flex child must expand */
  min-height: 0;    /* Required: allow internal scroll */
  height: 100%;     /* Required: inherit parent height */
}
```

### For Master-Detail Pages (KsSplitter)

```vue
<KsSplitter storageKey="unique-key" initialRatio="25">
  <template #left>
    <aside class="request-list">
      <h2>Requests</h2>
      <div class="items"><!-- flex: 1; min-height: 0; overflow-y: auto; --></div>
    </aside>
  </template>
  <template #right>
    <main class="detail-panel">
      <!-- height: 100%; min-height: 0; overflow-y: auto; -->
    </main>
  </template>
</KsSplitter>
```

**Key**: KsSplitter pane uses `overflow: hidden`; each slot's scrollable child must have `overflow-y: auto; min-height: 0`.

### For Flex-Column Containers

```css
.container {
  display: flex;
  flex-direction: column;
  flex: 1;         /* Expand to fill parent */
  min-height: 0;   /* Allow internal overflow */
  height: 100%;    /* Inherit parent height (optional if flex: 1 works) */
}

.child {
  flex: 1;         /* Share space with siblings */
  min-height: 0;   /* Don't prevent scrolling */
  overflow-y: auto;/* Internal scroll */
}
```

---

## Standard CSS Classes (Optional Utilities)

Defined in `frontend/src/design-system/base.css`:

```css
.ks-flex-column-1 { display: flex; flex-direction: column; flex: 1; min-height: 0; }
.ks-flex-row-1    { display: flex; flex-direction: row; flex: 1; min-height: 0; }
.ks-overflow-auto { overflow-y: auto; }
```

**Note**: These are *opt-in* utilities. Prefer explicit CSS in scoped styles for clarity.

---

## Related Artifacts

- **Commits:**
  - 61ca979: `.ks-stack` flex: 1 fix
  - b299939: ApprovalQueue flex layout
  - 05e2791: ApprovalQueue → KsSplitter refactor
  - 4ff5aaf: `.request-detail` height fix
  - a1eccad: Standard CSS class definitions

- **Updated Components:**
  - VersionGovernancePage.vue
  - ApprovalQueue.vue (KsSplitter migration)
  - ModelOperationsPage.vue

- **Memory:** [[layout_standardization_framework]]

---

## Verification Checklist

For each new page:
- [ ] First load fits viewport (no page scroll)
- [ ] Internal panes have `overflow-y: auto; min-height: 0`
- [ ] Height chain: PageLayout → QueryBoundary → content
- [ ] Master-detail uses KsSplitter or equivalent flex layout
- [ ] All flex children have `flex: 1; min-height: 0`

---

## Future Considerations

1. **Breakpoints**: Responsive layouts (mobile) may need `flex-direction: column` at small widths
2. **Height variants**: Consider separate classes for different flex ratios (1:2, 1:1, etc.)
3. **Template enforcement**: CI/CD gate to catch missing height constraints

---

## Questions?

See CLAUDE.md §"Frontend: Vue 3 + Vite + KBX Foundation v4" for component architecture.
