/* ==========================================================================
   ds-converter.css — Phase 3/4: the live conversion experience.
   Requires ds.css + ds-components.css. Scoped under .dsc.

   Brief 162: this is the signature moment. The layout is a single continuous
   panel that transforms between states rather than swapping screens.
   ========================================================================== */

.dsc {
  --dsc-gap: var(--s-5);
  max-width: 1060px;
  margin-inline: auto;
}

.dsc-shell {
  position: relative;
  background: var(--c-surface);
  border: 1px solid var(--c-line);
  border-radius: var(--r-panel);
  box-shadow: var(--e-card);
  overflow: hidden;
}

/* Thin progress rail across the very top of the panel. */
.dsc-rail { position: absolute; inset: 0 0 auto 0; height: 3px; background: var(--c-bg-sunk); z-index: 2; }
.dsc-rail span {
  display: block; height: 100%; width: 0;
  background: linear-gradient(90deg, var(--c-green), var(--c-green-bright));
  transition: width var(--t-slow) var(--ease-out);
}
.dsc-shell[data-state="idle"] .dsc-rail { opacity: 0; }

/* ---- Toolbar ---------------------------------------------------------- */
.dsc-bar {
  display: flex; align-items: center; justify-content: space-between;
  gap: var(--s-4); flex-wrap: wrap;
  padding: var(--s-4) var(--s-5);
  border-bottom: 1px solid var(--c-line);
}
.dsc-bar-l { display: flex; align-items: center; gap: var(--s-3); flex-wrap: wrap; }
.dsc-bar-r { display: flex; align-items: center; gap: var(--s-3); flex-wrap: wrap; }
.dsc-hint { font-size: var(--fs-caption); color: var(--c-ink-3); }

/* ---- Stage ------------------------------------------------------------ */
.dsc-stage {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: var(--dsc-gap);
  padding: var(--s-5);
  transition: grid-template-columns var(--t-slow) var(--ease-out);
}
/* Once work starts the panel splits: document left, live sheet right. */
.dsc-shell[data-state="uploading"] .dsc-stage,
.dsc-shell[data-state="processing"] .dsc-stage,
.dsc-shell[data-state="success"] .dsc-stage {
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
}

/* ...but only once there is something to put in the right-hand column.
   Splitting on state alone opened a half-width, 320px-tall empty sheet the
   moment the upload started and left it there — often for most of the run —
   reading as a broken layout rather than as work in progress. The split is
   therefore driven by the real row count, which ds-converter.js writes to
   data-rows. Until the first extracted row arrives the stage is one centred
   column. No placeholder rows are ever drawn. */
.dsc-shell[data-rows="0"] .dsc-stage { grid-template-columns: minmax(0, 1fr); }
.dsc-shell[data-rows="0"] #dscRight { display: none !important; }
.dsc-shell[data-rows="0"] #dscLeft { width: 100%; max-width: 580px; margin-inline: auto; }

/* ---- Dropzone (brief 36) ---------------------------------------------- */
.dsc-drop {
  position: relative; isolation: isolate;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  text-align: center; gap: var(--s-3);
  min-height: 280px; padding: var(--s-6);
  border: 1.5px dashed var(--c-line-strong);
  border-radius: var(--r-card);
  background: linear-gradient(180deg, var(--c-bg-soft), var(--c-surface));
  cursor: pointer;
  transition: border-color var(--t-normal) var(--ease-inout),
              background-color var(--t-normal) var(--ease-inout),
              transform var(--t-normal) var(--ease-out);
}
.dsc-drop:hover { border-color: var(--c-green-line); }
.dsc-drop.is-drag {
  border-color: var(--c-green); border-style: solid;
  background: var(--c-green-soft);
  transform: scale(1.005);
}
.dsc-title { font-size: var(--fs-h3); font-weight: var(--fw-semi); color: var(--c-ink); }
.dsc-sub { font-size: var(--fs-label); color: var(--c-ink-3); }
.dsc-browse {
  border: 0; background: none; padding: 0; font: inherit;
  color: var(--c-green-text); font-weight: var(--fw-semi);
  text-decoration: underline; text-underline-offset: 3px; cursor: pointer;
}

/* Custom document icon — no generic upload cloud (brief 36). */
.dsc-doc { width: 68px; height: 78px; position: relative; }
.dsc-doc svg { width: 100%; height: 100%; overflow: visible; }
.dsc-doc .page { transition: transform var(--t-normal) var(--ease-out); }
.dsc-doc .cellghost { opacity: 0; transition: opacity var(--t-normal) var(--ease-out),
                                              transform var(--t-normal) var(--ease-out); }
/* Brief 37: on drag the document opens slightly and cells appear behind it. */
.dsc-drop.is-drag .dsc-doc .page { transform: translateY(-3px) rotate(-3deg); }
.dsc-drop.is-drag .dsc-doc .cellghost { opacity: 1; transform: translate(4px, 4px); }

/* ---- File card (brief 39) --------------------------------------------- */
.dsc-file {
  display: flex; align-items: center; gap: var(--s-3);
  padding: var(--s-3) var(--s-4);
  border: 1px solid var(--c-line); border-radius: var(--r-card);
  background: var(--c-surface);
}
.dsc-file .fi {
  width: 38px; height: 38px; flex: none; border-radius: var(--r-control);
  display: grid; place-items: center; background: var(--c-green-soft); color: var(--c-green-text);
}
.dsc-file .fm { min-width: 0; flex: 1; }
.dsc-file .fn {
  font-size: var(--fs-label); font-weight: var(--fw-semi); color: var(--c-ink);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.dsc-file .fs { font-size: var(--fs-caption); color: var(--c-ink-3); font-variant-numeric: tabular-nums; }

/* ---- Document / scanning panel (brief 42) ----------------------------- */
/* The page being read. Capped: as a stretched grid item it grew to match the
   sheet beside it and became a tall empty box with a few lines at the top. */
.dsc-scan {
  position: relative; overflow: hidden;
  border: 1px solid var(--c-line); border-radius: var(--r-card);
  background: var(--c-bg-soft); padding: var(--s-4);
  min-height: 190px; max-height: 260px;
  align-self: start;
}

/* home.css paints ::selection violet across the whole page. Inside the
   converter that legacy wash sat behind the stage labels and read as a
   broken highlight, so the island gets the accent it actually uses. */
.ds ::selection { background: var(--c-green-soft); color: var(--c-ink); }
.dsc-lines { display: grid; gap: 9px; }
.dsc-lines i {
  display: block; height: 7px; border-radius: 3px;
  background: var(--c-line-2); transition: background var(--t-fast);
}
.dsc-lines i.hot { background: var(--c-green-line); }
/* One subtle scanner line, not a light show. */
.dsc-scanline {
  position: absolute; left: 0; right: 0; height: 34px; pointer-events: none;
  background: linear-gradient(180deg, transparent, rgba(22,163,74,.13), transparent);
  border-top: 1px solid rgba(22,163,74,.35);
  animation: dscScan 2.6s var(--ease-inout) infinite;
}
@keyframes dscScan { 0% { top: -34px; } 100% { top: 100%; } }

/* ---- Live sheet (brief 44) -------------------------------------------- */
.dsc-sheet {
  border: 1px solid var(--c-line); border-radius: var(--r-card);
  background: var(--c-surface); overflow: hidden; display: flex; flex-direction: column;
  min-height: 260px;
}
.dsc-sheet-head {
  display: flex; align-items: center; justify-content: space-between;
  padding: var(--s-3) var(--s-4); border-bottom: 1px solid var(--c-line);
  font-size: var(--fs-caption); font-weight: var(--fw-strong);
  letter-spacing: .1em; text-transform: uppercase; color: var(--c-ink-3);
  background: var(--c-bg-soft); position: sticky; top: 0; z-index: 1;
}
.dsc-rows { overflow-y: auto; max-height: 320px; }

/* One column contract, shared by the header and every row, so the two can
   never drift apart. The date column is sized from its widest real content —
   a 10-character date at this size needs ~92px, and the old 62px is what
   pushed "01/27/2026" straight through the description beside it. */
.dsc-cols,
.dsc-row {
  display: grid;
  /* em terms so the columns grow with text zoom instead of being a fixed
     pixel width that 200% type immediately overruns. */
  grid-template-columns:
    var(--dsc-c-date, max(96px, 6.4em))
    minmax(0, 1fr)
    var(--dsc-c-amt,  max(112px, 7.4em));
  column-gap: var(--s-4);
  align-items: center;
  padding: 9px var(--s-4);
}
.dsc-cols {
  border-bottom: 1px solid var(--c-line-2);
  background: var(--c-surface-2);
  font-size: 10px; font-weight: var(--fw-strong);
  letter-spacing: .1em; text-transform: uppercase; color: var(--c-ink-faint);
  padding-block: 7px;
}
.dsc-cols span:last-child { text-align: right; }
.dsc-row { border-bottom: 1px solid var(--c-line); font-size: 13px; }
.dsc-row:last-child { border-bottom: 0; }
.dsc-row .d {
  color: var(--c-ink-3); font-variant-numeric: tabular-nums;
  font-family: var(--font-mono); font-size: 11.5px; white-space: nowrap;
}
/* Controlled ellipsis. The full string stays in title/aria, so nothing is
   lost — it just is not allowed to widen the grid. */
.dsc-row .n {
  min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  color: var(--c-ink);
}
/* Amounts share a decimal edge: the sign sits in its own slot on the left of
   the column so the digits themselves stay flush right. */
.dsc-row .a {
  display: grid; grid-template-columns: 1ch auto; justify-content: end;
  column-gap: 3px; align-items: baseline;
  font-variant-numeric: tabular-nums; font-weight: var(--fw-semi);
  font-family: var(--font-mono); font-size: 12.5px;
}
.dsc-row .a .sg { font-style: normal; opacity: .75; }
.dsc-row .a.neg { color: var(--c-danger); }
.dsc-row .a.pos { color: var(--c-green-text); }
/* New rows arrive from the document side: left, slightly blurred, then crisp. */
.dsc-row.is-new { animation: dscRowIn .30s var(--ease-out) both; }
@keyframes dscRowIn {
  from { opacity: 0; transform: translateX(-10px); filter: blur(2px); }
  to   { opacity: 1; transform: none; filter: none; }
}
/* Brief 43: the cell briefly takes the validated wash, then releases. */
.dsc-row.is-new .a { animation: dscCell 1.1s var(--ease-out) both; }
@keyframes dscCell {
  0%, 40% { background: var(--c-green-soft); box-shadow: 0 0 0 3px var(--c-green-soft); }
  100%    { background: transparent; box-shadow: none; }
}
.dsc-empty { padding: var(--s-6); text-align: center; color: var(--c-ink-3); font-size: var(--fs-label); }

/* ---- Stages: a connected vertical stepper (brief 48-51) ----------------
   Five honest stages, drawn as one progression. Each step owns a marker and
   the rail is a pseudo-element between markers, so the states cannot drift
   apart the way a separate progress bar would. */
.dsc-meta { display: grid; gap: var(--s-3); margin-top: var(--s-5); }
.dsc-stages {
  display: grid; gap: 0;
  padding: var(--s-4) var(--s-4) var(--s-4) var(--s-3);
  border: 1px solid var(--c-line);
  border-radius: var(--r-card);
  background: var(--c-surface);
}
.dsc-step {
  position: relative;
  display: grid; grid-template-columns: 22px minmax(0, 1fr);
  column-gap: var(--s-3); align-items: center;
  min-height: 34px;
  font-size: var(--fs-label);
  color: var(--c-ink-3);
  transition: color var(--t-normal) var(--ease-inout);
}
/* The rail. Drawn downward from each marker except the last, behind them. */
.dsc-step:not(:last-child)::before {
  content: ""; position: absolute; left: 10px; top: 50%; bottom: -50%;
  width: 2px; margin-left: -1px;
  background: var(--c-line-2);
  transition: background-color var(--t-slow) var(--ease-out);
}
.dsc-step[data-done="true"]:not(:last-child)::before { background: var(--c-green); }

.dsc-mark {
  position: relative; z-index: 1;
  width: 20px; height: 20px; border-radius: 50%;
  display: grid; place-items: center;
  background: var(--c-surface);
  border: 2px solid var(--c-line-2);
  color: var(--c-on-green);
  transition: background-color var(--t-normal) var(--ease-out),
              border-color var(--t-normal) var(--ease-out),
              transform var(--t-normal) var(--ease-pop);
}
.dsc-mark .tick {
  width: 12px; height: 12px;
  stroke-dasharray: 16; stroke-dashoffset: 16;
  transition: stroke-dashoffset 220ms var(--ease-out);
}

/* Upcoming — hollow ring, quiet label. */
.dsc-step[data-on="false"][data-done="false"] .dsc-mark { background: var(--c-surface); }

/* Active — filled ring with a slow breath, so "working" is legible without
   inventing a percentage. */
.dsc-step[data-on="true"] { color: var(--c-ink); font-weight: var(--fw-semi); }
.dsc-step[data-on="true"] .dsc-mark {
  border-color: var(--c-green);
  background: var(--c-green-soft);
  animation: dscPulse 1.6s var(--ease-inout) infinite;
}
@keyframes dscPulse {
  0%, 100% { box-shadow: 0 0 0 0 rgba(22,163,74,.30); }
  50%      { box-shadow: 0 0 0 5px rgba(22,163,74,0); }
}

/* Done — solid marker, check strokes in over 220ms. */
.dsc-step[data-done="true"] { color: var(--c-ink-2); }
.dsc-step[data-done="true"] .dsc-mark {
  background: var(--c-green); border-color: var(--c-green);
}
.dsc-step[data-done="true"] .dsc-mark .tick { stroke-dashoffset: 0; }

.dsc-step-label {
  min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  letter-spacing: -.005em;
  /* Nothing paints a background behind a stage label. A legacy violet
     selection wash used to sit behind every one of these. */
  background: none;
}

/* The summary total is only meaningful once the job reports it. While rows are
   still streaming it sat at "0 transactions" underneath a table that already
   showed seven, so it is held back until success — the sheet header carries
   the live row count in the meantime. */
.dsc-counts { display: flex; gap: var(--s-5); flex-wrap: wrap; }
.dsc-shell:not([data-state="success"]) .dsc-counts { display: none; }
.dsc-count b {
  display: block; font-size: 22px; font-weight: var(--fw-strong);
  font-variant-numeric: tabular-nums; letter-spacing: -.02em; color: var(--c-ink);
}
.dsc-count span { font-size: var(--fs-caption); color: var(--c-ink-3); }

/* ---- Notices: encrypted / error / truncated --------------------------- */
.dsc-notice {
  display: flex; gap: var(--s-3); align-items: flex-start;
  padding: var(--s-4); border-radius: var(--r-card);
  border: 1px solid var(--c-line); background: var(--c-bg-soft);
  font-size: var(--fs-label); color: var(--c-ink-2);
}
.dsc-notice.warn   { background: var(--c-warn-soft);   border-color: rgba(168,98,15,.28);  color: var(--c-warn); }
.dsc-notice.danger { background: var(--c-danger-soft); border-color: rgba(179,37,63,.25);  color: var(--c-danger); }
.dsc-notice b { display: block; color: inherit; margin-bottom: 2px; }
.dsc-shell.is-nudge { animation: nudge .32s var(--ease-out); }

/* ---- Success (brief 54-56) -------------------------------------------- */
/* ---- Completion: one screen per real output format --------------------- */
.dsc-done {
  display: grid; grid-template-columns: auto minmax(0, 1fr) auto;
  align-items: center; gap: var(--s-4);
  padding: var(--s-4);
  border: 1px solid var(--c-green-line);
  border-radius: var(--r-card);
  background: var(--c-green-soft);
}
.dsc-done-copy { min-width: 0; }
.dsc-done .t-h3 { margin: 0 0 3px; letter-spacing: -.015em; }
.dsc-done .dsc-hint {
  display: flex; align-items: center; gap: var(--s-2); flex-wrap: wrap;
  font-family: var(--font-mono); font-size: 11.5px; color: var(--c-ink-2);
}

/* Format badge — the icon and extension of the file being downloaded. */
.dsc-fmt-badge {
  display: grid; place-items: center; gap: 3px;
  width: 52px; padding: var(--s-2) 0;
  border-radius: var(--r-control);
  background: var(--c-surface);
  border: 1px solid var(--c-green-line);
  color: var(--c-green);
}
.dsc-fmt-badge svg { width: 22px; height: 22px; }
.dsc-fmt-badge b {
  font-family: var(--font-mono); font-size: 9px; font-weight: 500;
  letter-spacing: .08em; color: var(--c-ink-3);
}
/* Each format gets its own mark colour, but all three stay inside the green
   scheme's temperature — the JSON badge used #7c3aed, the old brand violet,
   which was the last purple left in an active stylesheet. */
.dsc-fmt-badge[data-fmt="csv"]  { color: #0f766e; }
.dsc-fmt-badge[data-fmt="json"] { color: var(--c-ink-2); }

/* Small green status chip, the reference's "Completed" pill. */
.dsc-chip {
  display: inline-flex; align-items: center; gap: 5px;
  padding: 3px 9px; border-radius: var(--r-pill);
  background: var(--c-surface); border: 1px solid var(--c-green-line);
  color: var(--c-green-text); font-size: 11px; font-weight: var(--fw-semi);
}

/* CSV / JSON preview — the shape of the file, not a spreadsheet grid. */
.dsc-raw {
  margin: 0; padding: var(--s-4);
  font-family: var(--font-mono); font-size: 11.5px; line-height: 1.75;
  color: var(--c-ink-2); background: var(--c-surface);
  white-space: pre; overflow: auto; max-height: 320px;
  tab-size: 2;
}

@media (max-width: 560px) {
  .dsc-done { grid-template-columns: auto minmax(0, 1fr); }
  .dsc-done .check { display: none; }
}
.dsc-done .sum { display: flex; gap: var(--s-5); flex-wrap: wrap; }
.dsc-actions { display: flex; gap: var(--s-3); flex-wrap: wrap; margin-top: var(--s-4); }

/* ---- Mobile (brief 105/106): staged, never a squeezed six-column table -- */
@media (max-width: 860px) {
  .dsc-shell[data-state="uploading"] .dsc-stage,
  .dsc-shell[data-state="processing"] .dsc-stage,
  .dsc-shell[data-state="success"] .dsc-stage { grid-template-columns: minmax(0, 1fr); }
  .dsc-scan { min-height: 150px; }
  .dsc-rows { max-height: 260px; }
}
/* Narrow columns: the date shortens and the amount tightens, but the three
   columns and their alignment survive rather than collapsing into overlap.
   Set on the shared custom properties so header and rows move together. */
@media (max-width: 700px) {
  .dsc-sheet { --dsc-c-date: max(78px, 5.6em); --dsc-c-amt: max(96px, 6.4em); }
  .dsc-cols, .dsc-row { column-gap: var(--s-3); padding-inline: var(--s-3); }
}
@media (max-width: 560px) {
  .dsc-stage { padding: var(--s-4); }
  .dsc-bar { padding: var(--s-3) var(--s-4); }
  /* Below this width three columns cannot hold a real description, so each
     transaction becomes a two-line card: description over date, amount held
     to the right. The header row goes with the columns it described. */
  .dsc-cols { display: none; }
  .dsc-row {
    grid-template-columns: minmax(0, 1fr) auto;
    grid-template-areas: "name amt" "date amt";
    row-gap: 2px; padding: 10px var(--s-4); column-gap: var(--s-3);
  }
  .dsc-row .n { grid-area: name; white-space: normal; }
  .dsc-row .d { grid-area: date; font-size: 11px; }
  .dsc-row .a { grid-area: amt; align-self: center; font-size: 13px; }
  .dsc-drop { min-height: 220px; padding: var(--s-5); }
}

@media (prefers-reduced-motion: reduce) {
  .dsc-scanline { animation: none; opacity: .35; top: 40%; }
  .dsc-row.is-new, .dsc-row.is-new .a { animation: none; }
  .dsc-shell.is-nudge { animation: none; }
}

/* ==========================================================================
   [hidden] must actually hide. Every component below sets display:flex/grid,
   and a class rule outranks the UA stylesheet's [hidden]{display:none}, so the
   empty error notice was rendering as a grey strip under the dropzone.
   ========================================================================== */
.dsc [hidden] { display: none !important; }

/* The section eyebrow still inherits the old violet gradient from home.css.
   Scope it to green inside the converter so the two systems do not clash
   while the rest of the page is migrated in a later phase. */
.ds .sec-tag,
#convert .sec-tag {
  background: none !important;
  -webkit-text-fill-color: var(--c-green-text) !important;
  color: var(--c-green-text) !important;
}
