/* Shared components — the interaction language common to all three tools.
 *
 * Anything a user touches that appears in more than one app is defined here
 * once: buttons, the file drop zone, the numbered step badge, cards, status
 * messages and the chart frame. Apps add their own layout on top but should not
 * restyle these.
 *
 * Link order is tokens.css, then this, then the app's own stylesheet.
 */

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

body {
  margin: 0;
  background: var(--page);
  color: var(--text);
  font-family: var(--font);
  font-size: 16px;
  line-height: 1.5;
}

/* ---- page column ------------------------------------------------------- */
/* One width for every tool. Wrap the page content in .page and nothing else
   needs to think about it. */

.page {
  max-width: var(--page-max);
  margin: 0 auto;
  padding: 0 var(--page-pad) 4rem;
}

/* ---- app chrome -------------------------------------------------------- */
/* Identical in every tool: a full-bleed bar carrying the way back and the
   app-level actions, then the title block in the page column below it. */

.app-bar {
  background: var(--surface);
  border-bottom: 1px solid var(--border);
}
.app-bar-inner {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  max-width: var(--page-max);
  margin: 0 auto;
  padding: 0.5rem var(--page-pad);
}
.app-bar .spacer { flex: 1 1 auto; }

/* Min-height matches a .small button, so the bar is the same height whether or
   not it has any buttons in it — settings.html has none. */
.app-nav {
  display: inline-flex;
  align-items: center;
  min-height: 2.125rem;
  gap: 0.4rem;
  color: var(--text-muted);
  font-size: 0.875rem;
  text-decoration: none;
}
.app-nav:hover { color: var(--accent); }

.app-header {
  max-width: var(--page-max);
  margin: 0 auto;
  padding: 1.75rem var(--page-pad) 0;
}
.app-header h1 {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  margin: 0;
  font-size: 1.5rem;
}
.app-icon { display: inline-flex; flex: none; }
.app-icon svg { display: block; }

.header-actions { display: flex; gap: 0.5rem; flex: none; }

/* An <a> that has to sit alongside real buttons. */
.btn-link {
  display: inline-flex;
  align-items: center;
  font: inherit;
  font-size: 0.875rem;
  padding: 0.35rem 0.7rem;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  background: transparent;
  color: var(--text);
  text-decoration: none;
  transition: border-color 120ms, color 120ms;
}
.btn-link:hover { border-color: var(--accent); color: var(--accent); }
.btn-link:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

/* ---- buttons ----------------------------------------------------------- */

button {
  font: inherit;
  font-size: 0.9375rem;
  padding: 0.5rem 0.875rem;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  background: var(--surface);
  color: var(--text);
  cursor: pointer;
  transition: background 120ms, border-color 120ms, color 120ms, opacity 120ms;
}
button:hover:not(:disabled) { border-color: var(--accent); color: var(--accent); }
button:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
button:disabled { opacity: 0.5; cursor: not-allowed; }

button.primary {
  background: var(--accent);
  border-color: var(--accent);
  color: var(--accent-ink);
}
button.primary:hover:not(:disabled) {
  background: var(--accent);
  color: var(--accent-ink);
  filter: brightness(1.08);
}

button.ghost { background: transparent; }
button.secondary { background: var(--surface-2); }
button.small { padding: 0.35rem 0.7rem; font-size: 0.875rem; }
button.danger { color: var(--danger); }
button.danger:hover:not(:disabled) { border-color: var(--danger); color: var(--danger); }

/* ---- file drop --------------------------------------------------------- */
/* One upload control everywhere. Clicking it opens the picker; dragging a file
   over it adds .filedrop--active. */

.filedrop {
  display: block;
  width: 100%;
  margin-top: 1.5rem;
  padding: 3rem 1.5rem;
  border: 2px dashed var(--border);
  border-radius: var(--radius);
  background: transparent;
  text-align: center;
  color: var(--text-muted);
  cursor: pointer;
  transition: border-color 150ms, background 150ms, color 150ms;
}
.filedrop:hover,
.filedrop--active {
  border-color: var(--accent);
  background: var(--accent-soft);
  color: var(--accent);
}
.filedrop:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.filedrop p { margin: 0; }
/* The drop zone is centred, so a numbered heading inside it must be too. */
.filedrop h2:has(> .step-num) { justify-content: center; }
.filedrop strong, .filedrop code { color: var(--text); }
.filedrop--active strong, .filedrop--active code { color: inherit; }

/* ---- file panel -------------------------------------------------------- */
/* The panel stays visible once a file is open — it shrinks to this bar rather
   than disappearing, so opening a different file is always one click away. */

.filepanel-loaded {
  display: flex;
  align-items: center;
  gap: 1rem;
  flex-wrap: wrap;
  margin-top: 1.5rem;
  padding: 0.7rem 0.9rem;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--surface-2);
  transition: border-color 150ms, background 150ms;
}
.filepanel-loaded--active { border-color: var(--accent); background: var(--accent-soft); }

.filepanel-info {
  display: flex;
  align-items: baseline;
  gap: 0.75rem;
  flex: 1 1 12rem;
  min-width: 0;
}
.filepanel-name {
  font-weight: 600;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.filepanel-detail { color: var(--text-muted); font-size: 0.875rem; }
.filepanel-actions { display: flex; gap: 0.5rem; flex: none; }

.filepanel-error:empty { display: none; }

/* ---- numbered steps ---------------------------------------------------- */
/* Every app walks the user through an ordered sequence; the badge makes that
   sequence visible and is numbered the same way in all three. */

.step {
  display: flex;
  align-items: center;
  margin: 2rem 0 0.5rem;
  font-size: 1.0625rem;
  font-weight: 600;
}

/* Headings carry the badge inline; :has aligns it properly where supported and
   the vertical-align is the fallback everywhere else. */
h1:has(> .step-num), h2:has(> .step-num), h3:has(> .step-num) {
  display: flex;
  align-items: center;
}

.step-num {
  vertical-align: -0.15em;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: none;
  width: 1.5rem;
  height: 1.5rem;
  margin-right: 0.5rem;
  border-radius: 50%;
  background: var(--accent);
  color: var(--accent-ink);
  font-size: 0.8125rem;
  font-weight: 700;
  line-height: 1;
}

/* ---- cards ------------------------------------------------------------- */

.card {
  padding: 1.25rem;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--surface);
  box-shadow: var(--shadow);
}
.card h2 {
  display: flex;
  align-items: center;
  margin: 0 0 0.5rem;
  font-size: 1.0625rem;
}

/* ---- status and messages ----------------------------------------------- */

.tagline { margin: 0; color: var(--text-muted); font-size: 0.9375rem; }
.hint { margin: 0 0 0.875rem; color: var(--text-muted); font-size: 0.9375rem; }
.hint.tiny { font-size: 0.8125rem; }

.status { margin-top: 1rem; color: var(--text-muted); }

/* A failure says what went wrong (strong) and why or what to do about it
   (muted). Both apps that only managed the first half were the harder ones to
   recover from. */
.error {
  display: flex;
  gap: 0.7rem;
  align-items: flex-start;
  margin-top: 1rem;
  padding: 0.75rem 0.9rem;
  border: 1px solid var(--danger);
  border-radius: var(--radius-sm);
  background: rgba(208, 59, 59, 0.08);
  color: var(--text);
}
.error > div { display: flex; flex-direction: column; gap: 0.15rem; }
.error strong { color: var(--danger); }
.error span:not(.error-icon) { color: var(--text-secondary); font-size: 0.9375rem; }
.error-icon { color: var(--danger); flex: none; line-height: 1.5; }

/* For the moment a tool is about to write a file. Distinct from .error (which
   reports something that already went wrong) and from an accent-tinted callout
   (which is just information). */
.caution {
  display: flex;
  gap: 0.7rem;
  align-items: flex-start;
  margin-top: 1rem;
  padding: 0.75rem 0.9rem;
  border: 1px solid rgba(217, 131, 36, 0.45);
  border-radius: var(--radius-sm);
  background: rgba(217, 131, 36, 0.09);
  font-size: 0.9375rem;
}
.caution > div { display: flex; flex-direction: column; gap: 0.25rem; }
.caution strong { color: var(--warning); }
.caution-icon { color: var(--warning); flex: none; line-height: 1.5; }

.summary {
  margin-top: 1.25rem;
  padding: 0.6rem 0.9rem;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  background: var(--surface-2);
  font-size: 0.875rem;
}

.badge {
  display: inline-block;
  margin-right: 0.4rem;
  padding: 0.1rem 0.5rem;
  border: 1px solid var(--border);
  border-radius: var(--radius-pill);
  font-size: 0.75rem;
}

.hidden { display: none !important; }

/* ---- charts ------------------------------------------------------------ */
/* The frame only. What's drawn inside comes from shared/ui/chart-theme.js so
   that SVG, canvas and exported PNGs all agree. */

.chart {
  display: block;
  width: 100%;
  height: auto;
  border: 1px solid var(--border);
  border-radius: 8px;
  background: var(--surface);
}

/* ---- help modal -------------------------------------------------------- */
/* Namespaced deliberately. These were once plain .modal / .modal-panel, which
   collided with the swim corrector's own split dialog — that dialog's panel is
   also a .modal, and it does not set position or display, so it inherited
   `position: fixed; inset: 0; display: flex` from here and laid itself out
   across the viewport with its head, body and footer in a row. Anything shared
   that carries layout this assertive needs a name no app would pick. */

.help-modal { position: fixed; inset: 0; z-index: 100; display: flex; align-items: center; justify-content: center; }
.help-modal.hidden { display: none; }
.help-modal-backdrop { position: absolute; inset: 0; background: rgba(10, 15, 25, 0.55); }
.help-modal-panel {
  position: relative; background: var(--surface); color: var(--text);
  border: 1px solid var(--border); border-radius: var(--radius); box-shadow: var(--shadow);
  max-width: 760px; width: calc(100% - 32px); max-height: calc(100vh - 64px);
  overflow: auto; padding: 24px 28px;
}
.help-modal-close {
  position: absolute; top: 10px; right: 12px; border: none; background: transparent;
  font-size: 24px; line-height: 1; color: var(--text-muted); cursor: pointer; padding: 4px 8px;
}
.help-modal-close:hover { color: var(--text); }

.markdown { line-height: 1.6; }
.markdown h1 { font-size: 24px; margin: 0 0 12px; }
.markdown h2 { font-size: 19px; margin: 22px 0 8px; border-top: 1px solid var(--border); padding-top: 16px; }
.markdown h3 { font-size: 16px; margin: 18px 0 6px; }
.markdown p { margin: 0 0 12px; }
.markdown ul, .markdown ol { margin: 0 0 12px; padding-left: 22px; }
.markdown li { margin: 4px 0; }
.markdown a { color: var(--accent); }
.markdown code {
  background: var(--surface-2); border: 1px solid var(--border); border-radius: 4px;
  padding: 1px 5px; font-size: 0.9em; font-family: var(--font-mono);
}
