/* =============================================================================
   Translator — one stylesheet, no build step.

   THE ALIGNMENT RULE
   ------------------
   Both panes are cells of ONE css grid (#grid), four columns:

        [ line no. L ][ source ][ line no. R ][ target ]

   Line n of the source and line n of the target are cells of the same grid row,
   so the browser gives them the same height and the same vertical position, for
   free, forever. There is no scroll-sync code and no height-matching code,
   because there is one scroller and the layout engine does the matching. Editing
   a line cannot desynchronise the panes: it re-flows one grid row.

   The only javascript involved in alignment is the font auto-shrink, which makes
   a longer translation *fit* the row the source defined (see layout.js).
   ============================================================================ */

/* ---------------------------------------------------------------- tokens */
:root {
  --bar-h: 38px;
  --status-h: 22px;
  --head-h: 20px;

  --fs: 15px;              /* base editor font size  */
  --lh: 1.55;              /* base editor line height */
  --gw: 3.2ch;             /* gutter width */

  --fl: 1fr;               /* source column fraction (splitter writes these) */
  --fr: 1fr;               /* target column fraction */

  --font-ui: ui-sans-serif, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
  --font-ed: var(--font-ui);
  --font-mono: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace;

  --radius: 5px;
  --t: 120ms ease;
}

/* light */
body {
  --bg:        #ffffff;
  --bg-sunken: #f4f5f7;
  --bg-bar:    #fbfbfc;
  --bg-cell:   transparent;
  --bg-zebra:  #f7f8fa;
  --bg-hover:  #eef0f3;
  --bg-active: #e3e6ea;
  --fg:        #16181d;
  --fg-dim:    #6b7280;
  --fg-faint:  #9aa1ac;
  --line:      #e3e5e9;
  --line-soft: #eef0f3;
  --rule:      #d9e2f0;
  --rule-red:  #f0c9c9;
  --accent:    #2563eb;
  --accent-fg: #ffffff;
  --mark:      #fff3a3;
  --mark-fg:   #16181d;
  --ok:        #15803d;
  --warn:      #b45309;
  --err:       #b91c1c;
  --pending:   #d97706;
  --shadow:    0 6px 24px rgba(16, 18, 24, .13), 0 1px 2px rgba(16, 18, 24, .08);
}

/* dark */
body.theme-dark {
  --bg:        #14161a;
  --bg-sunken: #101216;
  --bg-bar:    #191c21;
  --bg-cell:   transparent;
  --bg-zebra:  #1a1d22;
  --bg-hover:  #23272e;
  --bg-active: #2c313a;
  --fg:        #e6e8ec;
  --fg-dim:    #9098a4;
  --fg-faint:  #656d79;
  --line:      #2a2e35;
  --line-soft: #22262c;
  --rule:      #2b3648;
  --rule-red:  #4a2b2b;
  --accent:    #60a5fa;
  --accent-fg: #0b1220;
  --mark:      #7a6414;
  --mark-fg:   #fdf6d8;
  --ok:        #4ade80;
  --warn:      #fbbf24;
  --err:       #f87171;
  --pending:   #fbbf24;
  --shadow:    0 6px 24px rgba(0, 0, 0, .5), 0 1px 2px rgba(0, 0, 0, .4);
}

* { box-sizing: border-box; }

html, body {
  height: 100%;
  margin: 0;
  overflow: hidden;               /* the grid scroller is the only scroller */
}

body {
  background: var(--bg);
  color: var(--fg);
  font: 400 13px/1.4 var(--font-ui);
  -webkit-text-size-adjust: 100%;
  display: flex;
  flex-direction: column;
}

/* =============================================================== toolbar */
.bar {
  height: var(--bar-h);
  flex: 0 0 var(--bar-h);
  display: flex;
  align-items: center;
  gap: 2px;
  padding: 0 6px;
  background: var(--bg-bar);
  border-bottom: 1px solid var(--line);
  user-select: none;
  overflow: hidden;
}

.grp {
  display: flex;
  align-items: center;
  gap: 1px;
  padding: 0 4px;
  border-right: 1px solid var(--line);
  height: 24px;
}
.grp:last-of-type { border-right: 0; }
.spacer { flex: 1 1 auto; }

/* icon button */
.ib {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 24px;
  height: 24px;
  padding: 0 4px;
  border: 0;
  border-radius: var(--radius);
  background: transparent;
  color: var(--fg-dim);
  font: 600 12px/1 var(--font-ui);
  cursor: pointer;
  transition: background var(--t), color var(--t);
}
.ib:hover  { background: var(--bg-hover); color: var(--fg); }
.ib:active { background: var(--bg-active); }
.ib.on     { background: var(--accent); color: var(--accent-fg); }
.ib.tgl.on { background: color-mix(in srgb, var(--accent) 18%, transparent); color: var(--accent); }
.ib svg {
  width: 15px; height: 15px;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.4;
  stroke-linecap: round;
  stroke-linejoin: round;
}
.ib.hl span {
  background: var(--mark);
  color: var(--mark-fg);
  padding: 0 3px;
  border-radius: 2px;
}
.ib.busy svg { animation: spin .9s linear infinite; }
@keyframes spin { to { transform: rotate(360deg); } }

/* selects + title */
.sel {
  height: 24px;
  max-width: 128px;
  border: 1px solid transparent;
  border-radius: var(--radius);
  background: transparent;
  color: var(--fg);
  font: 500 12px/1 var(--font-ui);
  padding: 0 2px;
  cursor: pointer;
  appearance: none;
  text-align: center;
  text-align-last: center;
}
.sel:hover { background: var(--bg-hover); }
.sel:focus-visible, .title:focus-visible, .ib:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: -1px;
}
.sel.lang { width: 92px; }
.sel.prov { width: 112px; }

.title {
  width: 150px;
  height: 24px;
  border: 1px solid transparent;
  border-radius: var(--radius);
  background: transparent;
  color: var(--fg);
  font: 600 12.5px/1 var(--font-ui);
  padding: 0 6px;
}
.title:hover { background: var(--bg-hover); }
.title:focus { background: var(--bg); border-color: var(--line); outline: none; }

/* =============================================================== stage */
.stage {
  flex: 1 1 auto;
  min-height: 0;
  position: relative;
  display: flex;
  flex-direction: column;
  background: var(--bg);
}

/* pane headers — 20px, purely informational */
.heads {
  flex: 0 0 var(--head-h);
  height: var(--head-h);
  display: grid;
  grid-template-columns: var(--gw-l, 0px) minmax(0, var(--fl)) var(--gw-r, 0px) minmax(0, var(--fr));
  border-bottom: 1px solid var(--line-soft);
  background: var(--bg-bar);
  font: 600 10px/var(--head-h) var(--font-ui);
  letter-spacing: .04em;
  text-transform: uppercase;
  color: var(--fg-faint);
  user-select: none;
}
.head { padding: 0 10px; overflow: hidden; white-space: nowrap; }
.head-l { grid-column: 2; }
.head-r { grid-column: 4; border-left: 1px solid var(--line-soft); }

.scroll {
  flex: 1 1 auto;
  min-height: 0;
  overflow: auto;
  overscroll-behavior: contain;
  scrollbar-gutter: stable;
}

/* ---------------------------------------------------------------- THE GRID */
.grid {
  display: grid;
  grid-template-columns: var(--gw-l, 0px) minmax(0, var(--fl)) var(--gw-r, 0px) minmax(0, var(--fr));
  align-content: start;
  min-height: 100%;
  padding-bottom: 40vh;            /* type near the bottom without it hugging */
  font-size: var(--fs);
}

/* gutters */
.num {
  font: 400 calc(var(--fs) * .72)/var(--lh) var(--font-mono);
  color: var(--fg-faint);
  text-align: right;
  padding: 2px 6px 2px 4px;
  user-select: none;
  background: var(--bg-sunken);
  border-right: 1px solid var(--line-soft);
  overflow: hidden;
}
.num-r { border-left: 1px solid var(--line-soft); }
.row-active .num { color: var(--accent); font-weight: 600; }

/* cells */
.cell {
  position: relative;
  padding: 2px 10px;
  min-width: 0;
  border-bottom: 1px solid transparent;
}
.cell-r { border-left: 1px solid var(--line-soft); }

/* the editable itself: natural height — this is what layout.js measures */
.ed {
  font-family: var(--font-ed);
  font-size: 1em;
  line-height: var(--lh);
  color: var(--fg);
  outline: none;
  white-space: pre-wrap;
  overflow-wrap: break-word;
  word-break: normal;
  min-height: calc(var(--fs) * var(--lh));
  caret-color: var(--accent);
}
.ed:empty::before {
  content: attr(data-ph);
  color: var(--fg-faint);
  pointer-events: none;
}
/* The target font scale. NOT transitioned on purpose: layout.js measures
   offsetHeight in a loop while choosing the scale, and an in-flight font-size
   animation would make every one of those measurements a lie. */
.cell-r .ed { font-size: calc(1em * var(--scale, 1)); }

/* rows are grid subgrids in spirit: `display: contents` lets one .row element
   carry the state classes while its four children remain grid items */
.row { display: contents; }

/* inline marks */
.ed b, .ed strong { font-weight: 700; }
.ed i, .ed em     { font-style: italic; }
.ed u             { text-decoration: underline; text-underline-offset: 2px; }
.ed s             { text-decoration: line-through; }
.ed mark          { background: var(--mark); color: var(--mark-fg); border-radius: 2px; padding: 0 1px; }

/* per-line status pip, top-right of the target cell */
.pip {
  position: absolute;
  top: 5px; right: 3px;
  width: 5px; height: 5px;
  border-radius: 50%;
  background: transparent;
  transition: background var(--t);
}
.row-pending  .pip { background: var(--pending); animation: pulse 1s ease-in-out infinite; }
.row-error    .pip { background: var(--err); }
.row-manual   .pip { background: var(--accent); }
.row-fallback .pip { background: var(--warn); }
@keyframes pulse { 50% { opacity: .25; } }

/* active row */
.row-active .cell { background: color-mix(in srgb, var(--accent) 5%, transparent); }

/* ------------------------------------------------- line-number visibility */
body.nums-none  { --gw-l: 0px;      --gw-r: 0px; }
body.nums-left  { --gw-l: var(--gw); --gw-r: 0px; }
body.nums-right { --gw-l: 0px;      --gw-r: var(--gw); }
body.nums-both  { --gw-l: var(--gw); --gw-r: var(--gw); }
body.nums-none  .num,
body.nums-left  .num-r,
body.nums-right .num-l { display: none; }

/* ------------------------------------------------------------ page styles */
/* plain: nothing */
body.page-ruled    .cell { border-bottom-color: var(--rule); }
body.page-notebook .cell { border-bottom-color: var(--rule); }
body.page-notebook .cell::before {
  content: "";
  position: absolute;
  left: 6px; top: 0; bottom: -1px;
  width: 1px;
  background: var(--rule-red);
}
body.page-grid .cell {
  border-bottom-color: var(--rule);
  background-image:
    repeating-linear-gradient(to right, var(--rule) 0 1px, transparent 1px calc(var(--fs) * 1.35));
  background-position: 0 0;
}
body.page-dots .cell {
  background-image: radial-gradient(var(--rule) 1px, transparent 1px);
  background-size: calc(var(--fs) * 1.35) calc(var(--fs) * var(--lh));
  background-position: 4px 4px;
}

/* zebra is an independent toggle: it combines with any page style */
body.zebra .row-odd .cell,
body.zebra .row-odd .num { background-color: var(--bg-zebra); }
body.zebra .row-active .cell { background-color: color-mix(in srgb, var(--accent) 6%, var(--bg-zebra)); }

/* ---------------------------------------------------------------- splitter */
.splitter {
  position: absolute;
  top: 0; bottom: 0;
  width: 9px;
  margin-left: -4px;
  cursor: col-resize;
  z-index: 5;
  background: transparent;
}
.splitter::after {
  content: "";
  position: absolute;
  left: 4px; top: 0; bottom: 0;
  width: 1px;
  background: var(--line);
  transition: background var(--t);
}
.splitter:hover::after, .splitter.drag::after { background: var(--accent); }
body.dragging { cursor: col-resize; user-select: none; }

/* =============================================================== status */
.status {
  height: var(--status-h);
  flex: 0 0 var(--status-h);
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 0 10px;
  background: var(--bg-bar);
  border-top: 1px solid var(--line);
  font: 500 11px/1 var(--font-ui);
  color: var(--fg-dim);
  user-select: none;
  white-space: nowrap;
  overflow: hidden;
}
.status .sep { color: var(--fg-faint); }
.status .dim { color: var(--fg-faint); }
.status .st.warn { color: var(--warn); }
.status .st.err  { color: var(--err); }
.status .st.ok   { color: var(--ok); }
#st-save { font-variant-numeric: tabular-nums; }

/* =============================================================== zen mode */
body.zen .bar,
body.zen .status { display: none; }
body.zen .heads  { opacity: .35; }

/* =============================================================== popover */
.popover {
  position: fixed;
  z-index: 50;
  min-width: 210px;
  max-width: min(420px, calc(100vw - 20px));
  max-height: min(70vh, 560px);
  overflow: auto;
  padding: 5px;
  background: var(--bg);
  border: 1px solid var(--line);
  border-radius: 8px;
  box-shadow: var(--shadow);
  font-size: 12.5px;
}
.popover h4 {
  margin: 6px 8px 4px;
  font: 600 10px/1 var(--font-ui);
  letter-spacing: .06em;
  text-transform: uppercase;
  color: var(--fg-faint);
}
.popover .item {
  display: flex;
  align-items: center;
  gap: 8px;
  width: 100%;
  padding: 6px 8px;
  border: 0;
  border-radius: var(--radius);
  background: transparent;
  color: var(--fg);
  font: 500 12.5px/1.3 var(--font-ui);
  text-align: left;
  cursor: pointer;
}
.popover .item:hover { background: var(--bg-hover); }
.popover .item .tick { width: 14px; color: var(--accent); flex: 0 0 14px; }
.popover .item .sub  { color: var(--fg-faint); font-weight: 400; font-size: 11px; }
.popover .item .rt   { margin-left: auto; color: var(--fg-faint); font-size: 11px; }
.popover .item.danger:hover { background: color-mix(in srgb, var(--err) 14%, transparent); color: var(--err); }
.popover hr { border: 0; border-top: 1px solid var(--line-soft); margin: 5px 4px; }

.popover label.field {
  display: block;
  padding: 5px 8px;
}
.popover label.field span {
  display: block;
  margin-bottom: 3px;
  font-size: 11px;
  color: var(--fg-dim);
}
.popover input[type=text], .popover input[type=password] {
  width: 100%;
  height: 26px;
  padding: 0 7px;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--bg-sunken);
  color: var(--fg);
  font: 400 12px/1 var(--font-ui);
}
.popover .hint { padding: 2px 8px 6px; color: var(--fg-faint); font-size: 11px; line-height: 1.45; }
.popover .btn {
  margin: 4px 8px 6px;
  padding: 6px 12px;
  border: 0;
  border-radius: var(--radius);
  background: var(--accent);
  color: var(--accent-fg);
  font: 600 12px/1 var(--font-ui);
  cursor: pointer;
}

/* =============================================================== toast */
.toast {
  position: fixed;
  left: 50%;
  bottom: calc(var(--status-h) + 14px);
  transform: translateX(-50%);
  z-index: 60;
  max-width: min(560px, calc(100vw - 24px));
  padding: 8px 14px;
  border-radius: 7px;
  background: var(--fg);
  color: var(--bg);
  font: 500 12px/1.45 var(--font-ui);
  box-shadow: var(--shadow);
  animation: rise 160ms ease;
}
.toast.err  { background: var(--err);  color: #fff; }
.toast.warn { background: var(--warn); color: #fff; }
@keyframes rise { from { opacity: 0; transform: translate(-50%, 6px); } }

/* =============================================================== gate */
.gate-body {
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--bg-sunken);
}
.gate {
  width: min(320px, calc(100vw - 32px));
  padding: 26px;
  background: var(--bg);
  border: 1px solid var(--line);
  border-radius: 10px;
  box-shadow: var(--shadow);
  text-align: center;
}
.gate h1 { margin: 0 0 4px; font-size: 17px; }
.gate p  { margin: 0 0 16px; color: var(--fg-dim); font-size: 12.5px; }
.gate input {
  width: 100%; height: 34px; margin-bottom: 10px;
  padding: 0 10px;
  border: 1px solid var(--line); border-radius: var(--radius);
  background: var(--bg-sunken); color: var(--fg); font-size: 13px;
}
.gate button {
  width: 100%; height: 34px;
  border: 0; border-radius: var(--radius);
  background: var(--accent); color: var(--accent-fg);
  font: 600 13px/1 var(--font-ui); cursor: pointer;
}
.gate-err { color: var(--err); margin: 0 0 10px; }

/* =============================================================== responsive */
@media (max-width: 900px) {
  .title { width: 96px; }
  .sel.lang { width: 76px; }
  .sel.prov { width: 92px; }
}
@media (max-width: 720px) {
  .grp-fmt .fmt[data-fmt="clear"] { display: none; }
  .title { display: none; }
}
@media (max-width: 560px) {
  :root { --fs: 14px; }
  .grp-view #btn-page, .grp-view #btn-nums { display: none; }
  #st-chars, #st-target { display: none; }
}

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { animation-duration: 0s !important; transition-duration: 0s !important; }
}

/* printing: two columns, no chrome */
@media print {
  .bar, .status, .splitter, .heads { display: none; }
  html, body { height: auto; overflow: visible; }
  .scroll { overflow: visible; }
  .grid { padding-bottom: 0; }
  .cell { break-inside: avoid; }
}
