# ScopeDOPE UI Style Guide

Developer reference for the ScopeDOPE design system. All tokens and components are defined in
`app/src/main/java/com/coldboreballisticsllc/scopedope/ui/`.

---

## Design Principles

- **Dark instrument aesthetic.** The app looks and feels like precision measurement equipment —
  amber-on-dark, monospace data values, corner brackets on panels.
- **Unified data font.** Every number — results, inputs, DOPE values — uses the same 20sp bold
  IBM Plex Mono (`DataValueStyle`). Consistency at a glance is more valuable than visual hierarchy.
- **Touch-first sizing.** Minimum interactive height is 60dp for content rows, 68dp for primary
  buttons, 72dp for the bottom nav bar.
- **ScopeDOPE is a Ballistic Computer.** Never use the word "calculator" in any UI copy.

---

## Color Tokens

Defined in `ui/theme/Color.kt`.

| Constant | Hex | Usage |
|---|---|---|
| `ColorBackground` | `#0F1112` | Screen background |
| `ColorSurface` | `#181C1E` | Panel / card / bottom nav surface |
| `ColorSurface2` | `#202528` | Secondary surfaces; inactive tab bg; disabled button bg |
| `ColorBorder` | `#2A2E30` | All 1dp borders; dividers |
| `ColorAmber` | `#F0A500` | Primary accent — active states, CTA fill, active tab indicator |
| `ColorAmberDim` | `#B07A10` | Panel corner brackets; inactive amber elements |
| `ColorTextPrimary` | `#E8E4DC` | Body text; field values |
| `ColorTextMuted` | `#9A9690` | Field labels; secondary text; inactive nav labels |
| `ColorTextDisabled` | `#4A4744` | Disabled text; inactive toggle segments |
| `ColorDataPositive` | `#5A9E6F` | Positive elevation adjustments; active "+" in sign toggle |
| `ColorDataNegative` | `#C0554A` | Negative elevation adjustments; active "-" in sign toggle |
| `ColorDataDist` | `#7EAFD4` | Distance values in DOPE and results tables |

---

## Typography

Defined in `ui/theme/Type.kt`. Use the named constants directly — do not use M3 Typography slots
for data values (those slots have implicit line height and tracking unsuitable for tabular data).

| Constant | Size | Weight | Font | Primary Usage |
|---|---|---|---|---|
| `HeroElevationStyle` | 74sp | Bold | IBM Plex Mono | Hero card elevation value |
| `HeroWindStyle` | 38sp | Bold | IBM Plex Mono | Hero card wind value |
| `DataValueStyle` | 20sp | Bold | IBM Plex Mono | All data cells; numeric field input text |
| `TableHeaderStyle` | 18sp | SemiBold | IBM Plex Mono | Results table column headers |
| `PanelLabelStyle` | 15sp | Bold | IBM Plex Mono | `InstrumentPanel` floating labels |
| `ActionButtonStyle` | 30sp | Bold | IBM Plex Mono | `ActionButton` text |
| `NavLabelStyle` | 12sp | Medium | IBM Plex Mono | Bottom nav tab labels |
| `FieldLabelStyle` | 12sp | Medium | IBM Plex Mono | `NumericField` / `LabelTextField` labels |
| `BodyStyle` | 17sp | Normal | Inter | General prose, descriptions |
| `BodySubStyle` | 14sp | Normal | Inter | Secondary body text, subtitles |
| `HeroSubStyle` | 13sp | Normal | Inter | Hero card sub-labels |
| `SettingsBodyStyle` | 21sp | Normal | Inter | Settings rows (+25% scale vs BodyStyle) |
| `SettingsBodySubStyle` | 18sp | Normal | Inter | Settings secondary rows |
| `BadgeStyle` | 11sp | SemiBold | Inter | Small badges (e.g. "FIRE SOLUTION") |
| `ContextStripStyle` | 14sp | Normal | IBM Plex Mono | Context strip values |

---

## Components

Defined in `ui/components/Components.kt`.

---

### `InstrumentPanel`

Standard container for every data panel in the app. Every group of related inputs or outputs
should be wrapped in an `InstrumentPanel`.

```kotlin
InstrumentPanel(label = "Ammo") {
    // Column content here
}
```

**Anatomy:**
- 1dp `ColorBorder` border
- Floating label centered on the top border — visually clips it
  - Label text: `PanelLabelStyle`, `ColorAmberDim`, uppercased, with amber-dim dashes on each side
- TL corner bracket: 12dp amber-dim L-shape on top-left corner
- BR corner bracket: 12dp amber-dim L-shape on bottom-right corner
- Interior padding: 14dp all sides
- Background: `ColorSurface`

**When to use:** Any logical grouping of data — ammo info, rifle setup, DOPE entries, conditions,
output distances, sensor readout. Do not nest `InstrumentPanel`s.

---

### `ActionButton`

Primary action button. Used for all top-level actions (Calculate, Add, Print, Submit).

```kotlin
ActionButton(
    text    = "CALCULATE",
    onClick = { /* ... */ },
    modifier = Modifier.fillMaxWidth(),
    enabled  = true,
    height   = 68.dp,   // default
    notch    = 8.dp,    // default
)
```

**Variants:**

| Variant | `height` | `notch` | Usage |
|---|---|---|---|
| Primary (default) | 68dp | 8dp | Main screen CTA |
| Inline | 56dp | 6dp | Secondary actions within a panel (e.g. `+` in DOPE entry) |

**Disabled state:** `ColorSurface2` background, `ColorTextMuted` text. Use when action is not
yet available (e.g. not enough DOPE entries to calculate).

**Do not** use `ActionButton` for navigation actions — use `TextButton` or `IconButton`.

---

### `NotchedCornerShape`

Custom `Shape` used by `ActionButton`. Available for other surfaces that need the octagonal look.

```kotlin
val shape = remember(notch) { NotchedCornerShape(8.dp) }
Box(modifier = Modifier.clip(shape).background(ColorAmber)) { ... }
```

---

### `NumericField`

Text input for decimal numbers. Provides the standard label + `DataValueStyle` input combination.

```kotlin
NumericField(
    value         = zeroText,
    onValueChange = { zeroText = it },
    label         = "Zero Distance",
    suffix        = "yd",
    imeAction     = ImeAction.Next,
    focusRequester = zeroFocusRequester,  // optional
    onDone        = { /* called on IME done */ },
    onFocusLost   = { /* validate/save */ },
)
```

**Text style:** `DataValueStyle` (20sp bold Plex Mono). Do not override — consistency across all
numeric inputs is intentional.

**Colors:** Amber border on focus, `ColorBorder` unfocused, `ColorBackground` container.

---

### `LabelTextField`

Text input for string values (ammo names, session labels). Same layout as `NumericField` but
uses `KeyboardType.Text`.

```kotlin
LabelTextField(
    value         = nameText,
    onValueChange = { nameText = it },
    label         = "Ammo Name",
    imeAction     = ImeAction.Done,
    onFocusLost   = { saveAmmoName(nameText) },
)
```

---

### `LabeledValue`

Read-only key/value row. Used inside `InstrumentPanel` for display-only data.

```kotlin
LabeledValue(label = "Caliber", value = ".308 WIN")
LabeledValue(label = "BC G7",   value = "0.273", color = ColorAmber)
```

The value is always rendered in `BodySubStyle` with IBM Plex Mono font family.

---

### `SectionDivider`

1dp `ColorBorder` horizontal divider. Use between logical sections within a screen or panel.

```kotlin
SectionDivider(modifier = Modifier.padding(vertical = 8.dp))
```

---

## Spacing and Sizing

| Element | Size |
|---|---|
| Screen edge padding | 16dp |
| Between panels | 12dp |
| Inside panel (padding) | 14dp |
| Between field rows | 12dp |
| Bottom nav height | 72dp |
| Top app bar title | 30sp (via `AppTypography.titleLarge`) |
| Min touch target (rows) | 60dp |
| Min touch target (buttons) | 68dp (ActionButton default) |
| Corner bracket length | 12dp |
| Hero card corner bracket | 16dp |

---

## Bottom Navigation

Implemented as a custom `ScopeDopeBottomNav` composable in `ui/navigation/NavGraph.kt`.
Do **not** use M3 `NavigationBar` — it was replaced.

- 4 tabs: DOPE, COND, RESULTS, PRINT
- Active indicator: 2dp amber rect, 76% of tab width, at top of tab
- Active: `ColorAmber` icon + label + `ColorAmber.copy(alpha=0.07f)` bg
- Inactive: `ColorTextMuted` icon + label + `ColorBackground` bg
- System nav bar area: `Spacer` filled with `ColorSurface`, height from
  `WindowInsets.navigationBars.asPaddingValues().calculateBottomPadding()`

---

## DOPE Sign Toggle (+/-)

Used in the Add DOPE step of onboarding and in any future DOPE entry UI.
Shows "+/-" as a single annotated string using `buildAnnotatedString`:

- "+" → `ColorDataPositive` when adjustment is positive, `ColorTextDisabled` otherwise
- "/" → always `ColorTextDisabled`
- "-" → `ColorDataNegative` when adjustment is negative, `ColorTextDisabled` otherwise

This pattern must be used anywhere the user selects the sign of a scope adjustment. Do not
use separate "+" and "−" buttons.

---

## Results Table

- Fixed column widths (not weighted): Distance, Elevation, Wind, Clicks, Spin, Checkbox
- All cell values: `DataValueStyle` (20sp bold Plex Mono)
- Selected row: 3dp amber left rect drawn via `drawBehind`
- Checkbox: 33dp `Box`, amber background + "✓" when checked
- Positive elevation: `ColorDataPositive`; negative: `ColorDataNegative`
- Elevation sign always shown explicitly ("+2.3" / "−1.1")

---

## Screen Layout Pattern

Most screens follow this structure:

```
CenterAlignedTopAppBar (30sp title, navigation icon)
  Column (fillMaxSize, background ColorBackground, padding 16dp)
    InstrumentPanel("Panel Label") { ... }
    Spacer(12dp)
    InstrumentPanel("Panel Label") { ... }
    Spacer(weight 1f)   ← pushes action button to bottom
    ActionButton("ACTION", modifier = Modifier.fillMaxWidth())
```

Settings screens use `LazyColumn` with `heightIn(min = 68.dp)` on each row for touch compliance.

---

## Document Control

| Field | Value |
|---|---|
| **Document owner** | `jschwefel@coldboreballisticsllc.com` |
| **Classification** | Confidential (03_-_Confidential/) |
| **Location** | `OneDrive/CBB_Corporate/03_-_Confidential/Style_Guides/UI_DESIGN_STYLE_GUIDE.md` |
| **Cross-references** | `CODING_STYLE_GUIDE.md`; `BRAND_LEGAL_LANGUAGE_GUIDE.md` §5 (brand color palette — Cold Bore Blue, Bore Steel) |
| **Created** | 2026-06-04 |
| **Last updated** | 2026-06-11 |
| **Next full review due** | 2027-06-04 |

---

## Revision Control Block

| Rev | Date | Changed By | Reviewed By | Approved By | Summary |
|-----|------|------------|-------------|-------------|---------|
| 0.9 | 2026-06-04 | jschwefel | — | — | Initial release |
| DRAFT | 2026-06-09 | Claude Code | — | — | Corrected 3 color-token hex values to match the live `Color.kt` (ground truth): ColorTextPrimary #DDE3E8→#E8E4DC, ColorTextMuted #6B7280→#9A9690, ColorTextDisabled #3A3F42→#4A4744. Other 6 tokens, type sizes, and component specs verified correct against source. |
| DRAFT | 2026-06-11 | Claude Code | — | — | Added cross-reference to BRAND_LEGAL_LANGUAGE_GUIDE.md §5 for canonical brand color names (Cold Bore Blue, Bore Steel). |
