/* ==========================================================================
   OpenWays / WayKeeper design framework — waykeeper.css
   Source of truth for tokens and base component styles.
   See STYLE-GUIDE.md for rationale and usage rules.

   Brand note: "OpenWays" is the working brand; "WayKeeper" is the code
   placeholder. Nothing below hard-codes a wordmark — swap copy, not CSS.
   ========================================================================== */

/* --------------------------------------------------------------------------
   1. Tokens
   -------------------------------------------------------------------------- */
:root {
  /* Color — all text/background pairs meet WCAG 2.2 AA (ratios in STYLE-GUIDE.md) */
  --ow-paper:        #F5F7F4;  /* page background: cool mist white */
  --ow-surface:      #FFFFFF;  /* raised cards */
  --ow-panel:        #E9EFEA;  /* quiet inset panels */
  --ow-ink:          #24312B;  /* primary text: evergreen-slate */
  --ow-ink-soft:     #4A574F;  /* secondary text (7.0:1 on paper) */
  --ow-evergreen:    #2E5E4E;  /* brand: headings accents, verified tier (6.9:1) */
  --ow-action:       #4B2E83;  /* buttons, controls, focus: UW Husky purple (9.7:1) */
  --ow-link:         #2456A6;  /* text links only: conventional cobalt (6.6:1) */
  --ow-action-ink:   #FFFFFF;  /* text on action fills */
  --ow-amber-deep:   #755916;  /* partial tier text (6.1:1) */
  --ow-slate:        #4C5B66;  /* osm/proxy tier text (6.5:1) */
  --ow-gray:         #5C665F;  /* insufficient tier text, disabled labels */
  --ow-line:         #C8D2CB;  /* hairlines, quiet borders */
  --ow-warn-bg:      #F6EED8;  /* caveat panel fill; never a text color */
  --ow-error:        #8C2F26;  /* danger: destructive actions, form errors (7.6:1); mirrored as $danger in scss/_theme.scss; never decorative, never a tier color */

  /* Type */
  --ow-font-display: "Zilla Slab", "Rockwell", "Roboto Slab", serif;
  --ow-font-body:    "Atkinson Hyperlegible", "Segoe UI", system-ui, sans-serif;
  --ow-font-mono:    "IBM Plex Mono", ui-monospace, "Cascadia Mono", monospace;

  /* Scale — 18px body, ~1.25 ratio, in rem against the browser's 16px
     root so user font-size preferences scale everything. (Earlier values
     were mistakenly computed against an 18px root and rendered ~11% small.) */
  --ow-text-xs:   0.8125rem;  /* 13px  captions, badges */
  --ow-text-sm:   0.9375rem;  /* 15px  metadata, secondary UI */
  --ow-text-md:   1.125rem;   /* 18px  body */
  --ow-text-lg:   1.4375rem;  /* 23px  section intro, card titles */
  --ow-text-xl:   1.8125rem;  /* 29px  h2 */
  --ow-text-2xl:  2.25rem;    /* 36px  h1 on interior pages */
  --ow-text-3xl:  2.8125rem;  /* 45px  hero headline */

  /* Space — 4px base */
  --ow-s1: 0.25rem;  --ow-s2: 0.5rem;   --ow-s3: 0.75rem;
  --ow-s4: 1rem;     --ow-s6: 1.5rem;   --ow-s8: 2rem;
  --ow-s12: 3rem;    --ow-s16: 4rem;    --ow-s24: 6rem;

  /* Shape & stroke */
  --ow-radius: 6px;           /* one radius everywhere; signage corners, not pills */
  --ow-stroke: 3px;           /* the certainty-line weight */
  --ow-shadow: 0 2px 12px rgba(36, 49, 43, 0.18); /* ink-tinted, never black; floating chrome only */
  --ow-measure: 68ch;
}

/* --------------------------------------------------------------------------
   2. Base
   -------------------------------------------------------------------------- */
* { box-sizing: border-box; margin: 0; }

html { color-scheme: light; }

/* Division of labor with the Bootstrap layer (see scss/): Bootstrap+reboot
   loads FIRST and owns element normalization; this file loads AFTER and
   owns tokens, rhythm, and focus. The element reset below reclaims rhythm
   from reboot's default margins; spacing is applied by components. */
p, h1, h2, h3, h4, h5, h6, ul, ol, dl, hr, pre { margin: 0; }

/* Reboot covers form-control font inheritance too; kept so this file
   stands alone. */
button, input, optgroup, select, textarea { font: inherit; }

body {
  background: var(--ow-paper);
  color: var(--ow-ink);
  font-family: var(--ow-font-body);
  font-size: var(--ow-text-md);
  line-height: 1.6;
}

h1, h2, h3 {
  font-family: var(--ow-font-display);
  font-weight: 600;
  line-height: 1.15;
  letter-spacing: -0.01em;
}
h1 { font-size: var(--ow-text-3xl); }
h2 { font-size: var(--ow-text-xl); margin-block: var(--ow-s12) var(--ow-s4); }
h3 { font-size: var(--ow-text-lg); margin-block: var(--ow-s6) var(--ow-s2); }

p, li { max-width: var(--ow-measure); }
p + p { margin-top: var(--ow-s3); }

a {
  color: var(--ow-link); /* links stay cobalt: purple text links read as visited */
  text-decoration-thickness: 1.5px;
  text-underline-offset: 3px;
}
/* Hover drops the underline to 4px so skip-ink has no descenders to carve:
   a broken 3px bar would read as a dash, and dashes are the certainty
   line's reserved channel. */
a:hover { text-decoration-thickness: 3px; text-underline-offset: 4px; }

code, .ow-mono {
  font-family: var(--ow-font-mono);
  font-size: 0.85em;
  background: var(--ow-panel);
  padding: 0.1em 0.35em;
  border-radius: 4px;
}

/* Focus is a design feature, not a browser leftover. Everywhere, always. */
:focus-visible {
  outline: 3px solid var(--ow-action);
  outline-offset: 2px;
  border-radius: 2px;
}
/* Bootstrap's .btn swaps the outline for a translucent shadow ring no theme
   variable can fix; restore the one true ring (this file loads after). */
.btn:focus-visible {
  outline: 3px solid var(--ow-action);
  outline-offset: 2px;
  box-shadow: none;
}

/* Bootstrap quirk: its list-group hover normalization excludes .active
   (.list-group-item-action:not(.active):hover), so hovering the active
   item falls through to reboot's underlined a:hover. Underline is the
   prose-link signal; component items carry affordance via background. */
.list-group-item-action:hover,
.list-group-item-action:focus { text-decoration: none; }

/* Floating transient chrome (no backdrop of its own) gets the one quiet
   shadow: a figure-ground cue over arbitrary content, not decoration.
   Cross-cutting exception: Bootstrap gates per-component shadows behind
   $enable-shadows, which stays false so resting surfaces and form controls
   remain flat. Modal and offcanvas separate via their dimmed backdrop. */
.dropdown-menu, .popover, .toast { box-shadow: var(--ow-shadow); }

/* Destructive actions wear Bootstrap's danger semantics (--ow-error brick):
   btn-danger / btn-outline-danger on buttons, alert-danger / is-invalid on
   feedback. Menus have no danger item variant and the utility classes are
   not compiled, so this cross-cutting rule colors a destructive menu item.
   The ellipsis label and the confirmation dialog carry the meaning; the
   color reinforces it. Hover/focus keep the brick (Bootstrap's hover would
   otherwise reset it to ink); the background stays the quiet panel. */
.dropdown-item.ow-destructive,
.dropdown-item.ow-destructive:hover,
.dropdown-item.ow-destructive:focus { color: var(--ow-error); }

.ow-skip-link {
  position: absolute;
  left: var(--ow-s4);
  top: -4rem;
  background: var(--ow-ink);
  color: var(--ow-paper);
  padding: var(--ow-s2) var(--ow-s4);
  border-radius: var(--ow-radius);
  z-index: 10;
  transition: top 120ms ease-out;
}
.ow-skip-link:focus-visible { top: var(--ow-s4); }

/* Layout shell */
.ow-shell {
  max-width: 72rem;
  margin-inline: auto;
  padding: var(--ow-s8) var(--ow-s6) var(--ow-s24);
}

/* --------------------------------------------------------------------------
   3. The certainty line grammar
   Stroke style encodes data confidence, exactly as a map legend would.
   Tier meaning is ALWAYS carried by (pattern + text label); color is a
   reinforcement only. These classes style a border-top "specimen line" and
   feed the tier badges and cards below.
   -------------------------------------------------------------------------- */
/* Each tier = a color + a dash pattern, drawn as a gradient strip so the same
   grammar renders identically in specimen lines, badge swatches, and card
   edges (native border dashes can't vary dash length). */
.ow-tier-verified     { --tier-color: var(--ow-evergreen);  --tier-dash: linear-gradient(var(--tier-color), var(--tier-color)); }
.ow-tier-partial      { --tier-color: var(--ow-amber-deep); --tier-dash: repeating-linear-gradient(90deg, var(--tier-color) 0 14px, transparent 14px 22px); }
.ow-tier-osm          { --tier-color: var(--ow-slate);      --tier-dash: repeating-linear-gradient(90deg, var(--tier-color) 0 7px,  transparent 7px 13px); }
.ow-tier-proxy        { --tier-color: var(--ow-slate);      --tier-dash: repeating-linear-gradient(90deg, var(--tier-color) 0 3px,  transparent 3px 9px); }
.ow-tier-insufficient { --tier-color: var(--ow-gray);       --tier-dash: repeating-linear-gradient(90deg, var(--tier-color) 0 3px,  transparent 3px 15px); }

.ow-linespec {
  border: 0;
  height: var(--ow-stroke);
  width: 100%;
  background: var(--tier-dash, linear-gradient(var(--ow-line), var(--ow-line)));
  opacity: 1; /* reboot dims bare <hr>; certainty lines render at full strength */
}

/* Tier badge: pattern swatch + plain-text label. Never color alone.
   Use only on tier-scoped surfaces (tier cards, legends, map keys) where
   an edge or key gives the swatch context; in running text use
   .ow-tier-note below instead. */
.ow-tier-badge {
  display: inline-flex;
  align-items: center;
  vertical-align: middle;
  gap: var(--ow-s2);
  font-size: var(--ow-text-sm);
  font-weight: 700;
  color: var(--tier-color, var(--ow-ink));
}
.ow-tier-badge::before {
  content: "";
  width: 2rem;
  height: var(--ow-stroke);
  background: var(--tier-dash, linear-gradient(var(--ow-ink), var(--ow-ink)));
}

/* Compact tier note: the tier disclosure for prose contexts (modal bodies,
   confirmations, list rows). The certainty line reads as an edge, so here
   it is one: the top edge of a quiet panel. Never drop the bare badge
   swatch into a sentence. */
.ow-tier-note {
  position: relative;
  display: block;
  background: var(--ow-panel);
  padding: var(--ow-s2) var(--ow-s4);
  font-size: var(--ow-text-sm);
  /* deliberately square: this is an edge-marked strip, not a card */
}
.ow-tier-note::before {
  content: "";
  position: absolute;
  top: 0; left: 0; right: 0;
  height: var(--ow-stroke);
  background: var(--tier-dash, linear-gradient(var(--ow-line), var(--ow-line)));
}
.ow-tier-label { color: var(--tier-color, var(--ow-ink)); font-weight: 700; }

/* --------------------------------------------------------------------------
   4. Components
   -------------------------------------------------------------------------- */

/* Buttons come from the themed Bootstrap layer: btn btn-primary /
   btn-outline-primary (see scss/_theme.scss). Policy is unchanged: verbs,
   sentence case, one primary per resolved result; a disabled capability
   keeps its label and gains an adjacent plain-language reason. Semantics:
   <button> triggers an action in place, <a> navigates — both wear .btn. */

/* Cards */
.ow-card {
  background: var(--ow-surface);
  border: 1px solid var(--ow-line);
  border-radius: var(--ow-radius);
  padding: var(--ow-s6);
}
/* Tier-aware card: the certainty line is its top edge */
.ow-card--tier { position: relative; }
.ow-card--tier::before {
  content: "";
  position: absolute;
  top: -1px; left: -1px; right: -1px;
  height: var(--ow-stroke);
  background: var(--tier-dash, linear-gradient(var(--ow-line), var(--ow-line)));
  border-radius: var(--ow-radius) var(--ow-radius) 0 0;
}

/* Control row: the container for inline runs of buttons, chips, and tags.
   Components carry no outer margins; when a row wraps, spacing comes from
   the container's gap, never from the component. */
.ow-row { display: flex; flex-wrap: wrap; gap: var(--ow-s3); align-items: center; }

/* Card action stack: link buttons inside cards run full width, stacked.
   Buttons beside form controls and modal-footer actions stay inline. */
.ow-card-actions { display: grid; gap: var(--ow-s3); justify-items: start; margin-top: var(--ow-s4); }
.ow-card-actions .btn { width: 100%; }

.ow-card-grid {
  display: grid;
  gap: var(--ow-s4);
  grid-template-columns: repeat(auto-fit, minmax(16rem, 1fr));
}

/* Resource lifecycle status — plain text chip; a tag, not a traffic light */
.ow-status {
  display: inline-block;
  font-size: var(--ow-text-xs);
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--ow-ink-soft);
  background: var(--ow-panel);
  border: 1px solid var(--ow-line);
  border-radius: 4px;
  padding: 0.15em 0.6em;
}
.ow-status--existing { color: var(--ow-evergreen); border-color: var(--ow-evergreen); background: var(--ow-surface); }

/* Chooser: radio-group cards (relationship) and checkbox-free chips (intent) */
.ow-choice {
  display: block;
  position: relative;
  background: var(--ow-surface);
  border: 2px solid var(--ow-line);
  border-radius: var(--ow-radius);
  padding: var(--ow-s4);
  cursor: pointer;
}
.ow-choice:hover { border-color: var(--ow-ink-soft); }
.ow-choice:has(input:checked) { border-color: var(--ow-evergreen); background: #F0F6F2; }
.ow-choice:has(input:focus-visible) { outline: 3px solid var(--ow-action); outline-offset: 2px; }
.ow-choice input { position: absolute; opacity: 0; }
.ow-choice strong { display: block; font-family: var(--ow-font-display); font-size: var(--ow-text-lg); }
.ow-choice span { color: var(--ow-ink-soft); font-size: var(--ow-text-sm); }

.ow-chip {
  display: inline-block;
  position: relative;
  border: 2px solid var(--ow-line);
  border-radius: var(--ow-radius);
  background: var(--ow-surface);
  padding: var(--ow-s2) var(--ow-s4);
  font-size: var(--ow-text-sm);
  cursor: pointer;
}
.ow-chip:hover { border-color: var(--ow-ink-soft); }
.ow-chip:has(input:checked) { border-color: var(--ow-evergreen); background: #F0F6F2; font-weight: 700; }
.ow-chip:has(input:focus-visible) { outline: 3px solid var(--ow-action); outline-offset: 2px; }
.ow-chip input { position: absolute; opacity: 0; }
.ow-chip--recommended { border-style: dashed; } /* recommended = highlighted, never exclusive */

/* Content list: dash bullets, the house marker for prose lists. Opt-in;
   component lists (menus, chip rows, capability lists) style their own. */
.ow-list { list-style: none; padding: 0; display: grid; gap: var(--ow-s2); }
.ow-list li::before { content: "\2014\00A0"; color: var(--ow-ink-soft); }

/* Caveat / safety-rail panel: honest, in context, not a legal footer */
.ow-caveat {
  background: var(--ow-warn-bg);
  border-left: var(--ow-stroke) solid var(--ow-amber-deep);
  border-radius: 0 var(--ow-radius) var(--ow-radius) 0;
  padding: var(--ow-s4) var(--ow-s6);
  font-size: var(--ow-text-sm);
}
.ow-caveat strong { color: var(--ow-amber-deep); }

/* Route spine: vertical wayfinding rail marking the page's layers */
.ow-spine { position: relative; padding-left: var(--ow-s8); }
.ow-spine::before {
  content: "";
  position: absolute;
  left: 7px; top: 0.5rem; bottom: 0.5rem;
  border-left: var(--ow-stroke) solid var(--ow-evergreen);
}
.ow-spine-stop { position: relative; padding-block: var(--ow-s8) var(--ow-s4); }
.ow-spine-stop::before {
  content: "";
  position: absolute;
  left: calc(-1 * var(--ow-s8) + 1px);
  top: calc(var(--ow-s8) + 0.55em);
  width: 15px; height: 15px;
  border-radius: 50%;
  background: var(--ow-paper);
  border: var(--ow-stroke) solid var(--ow-evergreen);
}
.ow-eyebrow {
  font-size: var(--ow-text-xs);
  font-weight: 700;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--ow-evergreen);
}

/* Provenance line: the mono honesty voice at the bottom of any
   evidence-bearing card or list row — release IDs, snapshot dates, run
   parameters. One shared class so every surface speaks it identically
   (.ow-map-provenance in openways-map.css is its map-surface twin). */
.ow-provenance {
  font-family: var(--ow-font-mono);
  font-size: var(--ow-text-xs);
  color: var(--ow-ink-soft);
}

/* Iconography (see STYLE-GUIDE.md, Iconography). Chrome icons are inline
   Lucide SVGs (icons/lucide/, pinned version in icons/LICENSES.md).
   Icons are companions to text and never carry meaning alone; tiers never
   get icons (the certainty line is their mark). Decorative by default:
   aria-hidden="true" beside a visible label; aria-label only on icon-only
   controls in dense app chrome. Color always rides currentColor so icons
   obey the surrounding color semantics. Stroke width stays 2. */
.ow-icon {
  width: 1.2em;             /* scales with the context's type size */
  height: 1.2em;
  vertical-align: -0.22em;  /* optical baseline alignment beside text */
  flex-shrink: 0;
}

/* --------------------------------------------------------------------------
   5. Motion — one orchestrated moment (hero route draws in), micro elsewhere
   -------------------------------------------------------------------------- */
.ow-route-draw {
  stroke-dasharray: 1200;
  stroke-dashoffset: 1200;
  animation: ow-draw 1.4s ease-out 0.2s forwards;
}
@keyframes ow-draw { to { stroke-dashoffset: 0; } }

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { animation: none !important; transition: none !important; }
  .ow-route-draw { stroke-dashoffset: 0; }
}

@media (max-width: 40rem) {
  h1 { font-size: var(--ow-text-2xl); }
  .ow-shell { padding-inline: var(--ow-s4); }
  .ow-spine { padding-left: var(--ow-s6); }
  .ow-spine-stop::before { left: calc(-1 * var(--ow-s6) + 1px); }
}
