/* ============ workbench components ============ */

/* .glass is legacy-named — now it's just a flat bordered box */
.glass {
  background: var(--bg);
  border: 1px solid var(--line-2);
  border-radius: 0;
}

/* ---- panels (.tile) — bordered boxes with corner ticks ---- */
.tile {
  position: relative;
  background: var(--bg);
  border: 1px solid var(--line-2);
  border-radius: 0;
  padding: 14px 16px;
  transition: border-color var(--fast);
}
.tile:hover { border-color: var(--muted); }
/* corner ticks — the technical-drawing signature */
.tile::before, .tile::after {
  content: "+";
  position: absolute;
  color: var(--muted);
  font-size: 11px; line-height: 1;
  opacity: 0.7;
  pointer-events: none;
}
.tile::before { top: -6px; left: -4px; }
.tile::after { bottom: -6px; right: -4px; }
.sheen::after { content: "+"; } /* legacy class, same ticks */

/* ---- .marching — the "this one is live" outline ----------------------------
   A 1px dashed accent ring that crawls clockwise, plus hard corner brackets.
   Selection-marquee language: a DOS file manager, a Photoshop selection, an
   RTS unit you just clicked. It is the loudest thing this design system does,
   so it goes on the ONE element that is genuinely running and never on an
   idle one — the moment two things are marching it stops meaning anything.

   IT MUST STEP, NOT GLIDE. steps(12) over 0.9s advances the dashes one pixel
   roughly every 75ms — about 13fps. A smooth crawl reads as clean modern CAD;
   the low, visibly-quantised frame rate is the entire difference between that
   and something that looks like it came off a CRT. Do not "fix" this to a
   linear timing function.

   Needs both pseudo-elements. ::after is the ring, ::before is the brackets.
   The host gets position:relative from here, so it does not need its own. */
.marching { position: relative; }

.marching::after {
  content: "";
  position: absolute;
  inset: -1px;
  pointer-events: none;
  z-index: 2;
  /* four independent 1px edges: two horizontal, two vertical. Drawn as
     backgrounds rather than a border because a border cannot have its dashes
     offset per side, and per-side offset is what makes the crawl go round
     rather than each edge marching off on its own. */
  background-image:
    repeating-linear-gradient(90deg, var(--acc) 0 6px, transparent 6px 12px),
    repeating-linear-gradient(90deg, var(--acc) 0 6px, transparent 6px 12px),
    repeating-linear-gradient(180deg, var(--acc) 0 6px, transparent 6px 12px),
    repeating-linear-gradient(180deg, var(--acc) 0 6px, transparent 6px 12px);
  background-size: 100% 1px, 100% 1px, 1px 100%, 1px 100%;
  background-position: 0 0, 0 100%, 0 0, 100% 0;
  background-repeat: no-repeat;
  animation: march 0.9s steps(12) infinite;
}
/* top runs right, right runs down, bottom runs left, left runs up — one lap,
   one direction. Getting a sign wrong here makes the corners fight. */
@keyframes march {
  to { background-position: 12px 0, -12px 100%, 0 -12px, 100% 12px; }
}

/* corner brackets: a full 1px accent frame, masked down to its four corners.
   Cheaper and far more legible than eight positioned gradient slivers, and it
   inherits the exact geometry of the ring it sits outside. */
.marching::before {
  content: "";
  position: absolute;
  inset: -4px;
  pointer-events: none;
  z-index: 2;
  border: 1px solid var(--acc);
  -webkit-mask:
    linear-gradient(#000 0 0) 0 0 / 9px 9px no-repeat,
    linear-gradient(#000 0 0) 100% 0 / 9px 9px no-repeat,
    linear-gradient(#000 0 0) 0 100% / 9px 9px no-repeat,
    linear-gradient(#000 0 0) 100% 100% / 9px 9px no-repeat;
  mask:
    linear-gradient(#000 0 0) 0 0 / 9px 9px no-repeat,
    linear-gradient(#000 0 0) 100% 0 / 9px 9px no-repeat,
    linear-gradient(#000 0 0) 0 100% / 9px 9px no-repeat,
    linear-gradient(#000 0 0) 100% 100% / 9px 9px no-repeat;
  /* a two-frame drop, not a fade — steps(1) is what keeps it a hardware
     flicker rather than a designer's pulse */
  animation: ant-flicker 2.7s steps(1) infinite;
}
@keyframes ant-flicker {
  0%, 88% { opacity: 1; }
  92% { opacity: 0.35; }
  96% { opacity: 1; }
  98% { opacity: 0.55; }
  100% { opacity: 1; }
}

/* ---- .breathe — ambient life on something that is idle but awake ----------
   The counterpart to .marching. Where the marquee shouts "running now", this
   is the slow one: a live thing sitting still, still drawing breath. Used on
   the rung you currently hold and on the day counters.

   Stepped again, and deliberately only three frames — a smooth sine pulse is
   a wellness app, three hard steps is a sprite sheet. The amplitude is tiny on
   purpose: you should notice it only when you stop looking straight at it. */
.breathe { animation: breathe 3.4s steps(1) infinite; }
@keyframes breathe {
  0%, 100% { opacity: 1; }
  33% { opacity: 0.82; }
  66% { opacity: 0.93; }
}

/* ---- .tick — the counter snap ---------------------------------------------
   Toggled by JS the instant a displayed value changes. Two frames, no easing:
   the number jumps up a fraction and lands. This is the old arcade score
   counter, and it is what stops a clock from feeling like a spreadsheet cell
   quietly repainting itself.

   Kept at 120ms so it is finished before the next second arrives. */
.tick { animation: tick 120ms steps(2) 1; }
@keyframes tick {
  0% { transform: scale(1); }
  50% { transform: scale(1.055); }
  100% { transform: scale(1); }
}

/* ---- .snap — press feedback with no travel --------------------------------
   Hover and active states that move in one hard increment rather than gliding.
   A menu item in a game from before transitions existed: it is either in the
   normal position or the pressed one, never between them. */
.snap { transition: none !important; }
.snap:hover { transform: translate(-1px, -1px); }
.snap:active { transform: translate(1px, 1px); }

/* The global motion gate in base.css collapses animation-duration to 0.001s,
   which for an INFINITE STEPPED loop means it restarts a thousand times a
   second — a 1px strobe, which is exactly the thing reduced-motion exists to
   prevent. These have to be stopped outright rather than sped up. The dashes
   and brackets stay painted, so "this one is live" still reads without motion. */
:root.motion-off .marching::after,
:root.motion-off .marching::before,
:root.motion-off .breathe,
:root.motion-off .tick {
  animation: none !important;
}
:root.motion-off .snap:hover, :root.motion-off .snap:active { transform: none; }
@media (prefers-reduced-motion: reduce) {
  .marching::after, .marching::before, .breathe, .tick { animation: none !important; }
  .snap:hover, .snap:active { transform: none; }
}

/* "calm" keeps the life but halves the pulse rate — the marquee is the one
   thing that must not slow down, because a crawling selection box that crawls
   slowly reads as broken rather than as calm. */
:root.motion-calm .breathe { animation-duration: 6s; }

.tile-head {
  display: flex; align-items: baseline; gap: 8px;
  margin: -14px -16px 12px;
  padding: 7px 12px;
  border-bottom: 1px solid var(--line);
  background: var(--bg-2);
}
.tile-title {
  display: flex; align-items: center; gap: 7px;
  font-size: 0.68rem; font-weight: 700;
  letter-spacing: 0.12em; text-transform: uppercase;
  color: var(--ink-2);
}
.tile-title::before { content: "::"; color: var(--acc); font-weight: 700; }
.tile-title .ic { display: none; } /* icons out — text labels in */
.tile-link {
  margin-left: auto;
  font-size: 0.64rem; letter-spacing: 0.06em; text-transform: lowercase;
  color: var(--muted); background: none; border: none; padding: 2px 4px;
  text-decoration: none;
}
.tile-link:hover { color: var(--acc); }
.tile-link::after { content: " ->"; }
.tile-link .ic { display: none; }

/* ---- buttons: bordered, invert on hover ---- */
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 7px;
  font-size: 0.74rem; font-weight: 500;
  letter-spacing: 0.04em;
  padding: 7px 13px;
  border-radius: var(--r);
  border: 1px solid var(--line-2);
  background: var(--bg);
  color: var(--ink);
  transition: background var(--fast), color var(--fast), border-color var(--fast);
}
.btn:hover { background: var(--ink); color: var(--bg); border-color: var(--ink); }
.btn:active { transform: translate(1px, 1px); }
.btn.primary {
  background: var(--acc); color: var(--acc-ink); border-color: var(--acc);
  font-weight: 700;
}
.btn.primary:hover { background: var(--ink); border-color: var(--ink); color: var(--bg); }
.btn.ghost { border-color: transparent; background: transparent; color: var(--muted); }
.btn.ghost:hover { color: var(--ink); background: var(--bg-2); border-color: var(--line); }
.btn.danger { color: var(--bad); border-color: var(--bad); background: transparent; }
.btn.danger:hover { background: var(--bad); color: var(--bg); }
.btn.sm { padding: 4px 9px; font-size: 0.68rem; }
.btn:disabled { opacity: 0.45; pointer-events: none; }

.icon-btn {
  display: inline-grid; place-items: center;
  width: 26px; height: 26px;
  border-radius: var(--r);
  border: 1px solid transparent;
  background: transparent;
  color: var(--muted);
  transition: background var(--fast), color var(--fast), border-color var(--fast);
}
.icon-btn:hover { color: var(--ink); background: var(--bg-2); border-color: var(--line-2); }
.icon-btn.on { color: var(--acc); border-color: var(--acc); }
.icon-btn.danger:hover { color: var(--bad); border-color: var(--bad); }

/* ---- chips: lowercase mono tags, no pills ---- */
.chip-row { display: flex; gap: 4px 10px; flex-wrap: wrap; align-items: center; }
.chip {
  display: inline-flex; align-items: center; gap: 4px;
  font-size: 0.66rem;
  color: var(--muted);
  border: none; background: none;
  padding: 0;
  white-space: nowrap;
  text-transform: lowercase;
}
.chip::before { content: "["; color: var(--line-2); }
.chip::after { content: "]"; color: var(--line-2); }
.chip.c-ember { color: var(--acc); }
.chip.c-teal { color: var(--g-ledger); }
.chip.c-violet { color: var(--ok); }
.chip.c-cyan { color: var(--st-shaping); }
.chip.c-risk { color: var(--bad); }
.chip.removable { padding-right: 0; }
.chip .chip-x {
  display: grid; place-items: center;
  width: 13px; height: 13px;
  border: none; background: transparent; color: inherit; opacity: 0.55; padding: 0;
}
.chip .chip-x:hover { opacity: 1; color: var(--bad); }

.badge {
  display: inline-flex; align-items: center; gap: 3px;
  font-size: 0.68rem; font-weight: 500;
  font-variant-numeric: tabular-nums;
  padding: 0;
}
.badge.up { color: var(--ok); }
.badge.down { color: var(--bad); }
.badge.flat { color: var(--muted); }
.badge .ic { display: none; }
.badge.up::before { content: "▲"; font-size: 0.55rem; }
.badge.down::before { content: "▼"; font-size: 0.55rem; }

.status-dot { width: 7px; height: 7px; border-radius: 0; flex-shrink: 0; }

/* ---- inputs: flat field, accent focus ---- */
.input, textarea.input, select.input {
  width: 100%;
  background: var(--bg-2);
  border: 1px solid var(--line-2);
  border-radius: var(--r);
  color: var(--ink);
  padding: 7px 10px;
  font-size: 0.8rem;
  font-family: var(--mono);
  transition: border-color var(--fast), background var(--fast);
}
.input:hover { border-color: var(--muted); }
.input:focus { outline: none; border-color: var(--acc); background: var(--bg); }
textarea.input { min-height: 72px; resize: vertical; line-height: 1.5; }
select.input { cursor: pointer; }
.input::placeholder { color: var(--muted); opacity: 0.65; }
.field { margin-bottom: 12px; }
.label {
  display: block;
  font-size: 0.62rem; letter-spacing: 0.12em; text-transform: uppercase;
  color: var(--muted);
  margin-bottom: 4px;
}
.label::before { content: "· "; color: var(--acc); }

/* ---- loading: flat pulse + braille spinner ---- */
.skel {
  position: relative; overflow: hidden;
  background: var(--bg-3);
  border-radius: 0;
  animation: skel-pulse 1.1s ease-in-out infinite;
}
.skel::after { content: none; }
@keyframes skel-pulse { 0%, 100% { opacity: 0.55; } 50% { opacity: 1; } }
.skel-line { height: 11px; margin-bottom: 8px; }
.skel-line.w60 { width: 60%; }
.skel-line.w80 { width: 80%; }
.skel-line.w40 { width: 40%; }
.skel-block { height: 80px; }

.spinner { color: var(--acc); font-weight: 700; }

/* ---- empty / error ---- */
.empty {
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 8px;
  padding: 38px 20px;
  color: var(--muted);
  text-align: center;
  border: 1px dashed var(--line-2);
}
.empty .ic { display: none; }
.empty .em-kao { font-size: 1.1rem; color: var(--ink-2); letter-spacing: 0.05em; }
.empty p { margin: 0; max-width: 46ch; }
.empty .em-title { font-weight: 700; color: var(--ink-2); font-size: 0.85rem; text-transform: lowercase; }

.feed-error {
  display: flex; align-items: center; gap: 9px;
  padding: 9px 12px;
  border: 1px dashed var(--bad);
  color: var(--muted); font-size: 0.76rem;
}
.feed-error::before { content: "[!!]"; color: var(--bad); font-weight: 700; }
.feed-error .ic { display: none; }

/* ---- toasts: bottom-right log lines ---- */
#toast-root {
  position: fixed; bottom: 34px; right: 14px;
  display: flex; flex-direction: column; align-items: flex-end; gap: 6px;
  z-index: 90; pointer-events: none;
}
.toast {
  display: flex; align-items: center; gap: 8px;
  padding: 7px 12px;
  background: var(--bg);
  border: 1px solid var(--line-2);
  border-left: 3px solid var(--acc);
  font-size: 0.74rem;
  color: var(--ink);
  box-shadow: var(--hard-shadow);
  animation: toast-in 160ms ease both;
}
.toast.ok { border-left-color: var(--ok); }
.toast.err { border-left-color: var(--bad); }
.toast .ic { color: var(--muted); flex-shrink: 0; width: 13px; height: 13px; }
.toast.out { animation: toast-out 140ms ease both; }
@keyframes toast-in { from { opacity: 0; transform: translateX(10px); } to { opacity: 1; transform: none; } }
@keyframes toast-out { to { opacity: 0; transform: translateX(10px); } }

/* ---- modals: sharp box, hard offset shadow ---- */
.modal-bd {
  position: fixed; inset: 0;
  display: grid; place-items: center;
  background: color-mix(in srgb, var(--bg) 72%, transparent);
  z-index: 70;
  animation: fade-in var(--fast) ease both;
  padding: 20px;
}
.modal-bd.out { animation: fade-out var(--fast) ease both; }
@keyframes fade-in { from { opacity: 0; } to { opacity: 1; } }
@keyframes fade-out { to { opacity: 0; } }
.modal {
  width: 520px; max-width: 94vw; max-height: 86vh;
  overflow-y: auto;
  background: var(--bg);
  border: 1px solid var(--ink);
  border-radius: 0;
  padding: 18px 20px;
  box-shadow: var(--hard-shadow);
  animation: modal-in 170ms ease both;
}
.modal-bd.out .modal { animation: modal-out 120ms ease both; }
@keyframes modal-in { from { opacity: 0; transform: translate(4px, 4px); } to { opacity: 1; transform: none; } }
@keyframes modal-out { to { opacity: 0; transform: translate(4px, 4px); } }
.m-title {
  margin: -18px -20px 4px; padding: 10px 14px;
  border-bottom: 1px solid var(--line-2);
  background: var(--bg-2);
  font-size: 0.8rem; font-weight: 700;
  letter-spacing: 0.1em; text-transform: uppercase;
  display: flex; align-items: center; gap: 8px;
}
.m-title::before { content: "::"; color: var(--acc); }
.m-title .ic { display: none; }
.m-sub { color: var(--muted); margin: 10px 0 16px; }
.btn-row { display: flex; gap: 8px; margin-top: 16px; flex-wrap: wrap; }
.btn-row .spacer { flex: 1; }

/* ---- progress: block bars ---- */
.prog { height: 8px; background: var(--bg-3); overflow: hidden; border: 1px solid var(--line); }
.prog-bar {
  height: 100%;
  background: repeating-linear-gradient(90deg, var(--acc) 0 5px, transparent 5px 7px);
  transition: width 400ms ease;
}
.tbar { font-size: 0.72rem; color: var(--ink-2); letter-spacing: -0.5px; white-space: nowrap; }
.tbar b { color: var(--acc); font-weight: 400; }
.tbar .tb-n { color: var(--muted); letter-spacing: 0; margin-left: 7px; }

/* ---- command palette: a prompt ---- */
#palette-root .pal-bd {
  position: fixed; inset: 0;
  background: color-mix(in srgb, var(--bg) 66%, transparent);
  z-index: 80;
  display: flex; justify-content: center;
  padding-top: 11vh;
  animation: fade-in var(--fast) ease both;
}
#palette-root .pal-bd.out { animation: fade-out 100ms ease both; }
.pal-box {
  width: 600px; max-width: 92vw;
  height: fit-content; max-height: 64vh;
  display: flex; flex-direction: column;
  background: var(--bg);
  border: 1px solid var(--ink);
  box-shadow: var(--hard-shadow);
  overflow: hidden;
  animation: modal-in 150ms ease both;
}
.pal-input-row {
  display: flex; align-items: center; gap: 10px;
  padding: 11px 14px;
  border-bottom: 1px solid var(--line-2);
}
.pal-input-row .ic { display: none; }
.pal-input-row::before { content: ">"; color: var(--acc); font-weight: 700; }
.pal-input {
  flex: 1; border: none; outline: none; background: transparent;
  color: var(--ink); font-size: 0.9rem; font-family: var(--mono);
}
.pal-list { overflow-y: auto; padding: 4px 0; }
.pal-group {
  font-size: 0.6rem; letter-spacing: 0.16em; text-transform: uppercase;
  color: var(--muted); padding: 9px 14px 3px;
}
.pal-item {
  display: flex; align-items: center; gap: 9px;
  width: 100%;
  padding: 6px 14px;
  border: none; background: transparent;
  color: var(--ink-2); font-size: 0.8rem; text-align: left;
  font-family: var(--mono);
}
.pal-item .ic { width: 13px; height: 13px; color: var(--muted); flex-shrink: 0; }
.pal-item .pal-hint { margin-left: auto; font-size: 0.62rem; color: var(--muted); }
.pal-item b { color: var(--acc); font-weight: 700; }
.pal-item.sel { background: var(--ink); color: var(--bg); }
.pal-item.sel .ic, .pal-item.sel .pal-hint { color: var(--bg); opacity: 0.7; }
.pal-item.sel b { color: var(--acc); }
.pal-empty { padding: 22px; text-align: center; color: var(--muted); font-size: 0.78rem; }

/* ---- tables ---- */
.tbl { width: 100%; border-collapse: collapse; font-size: 0.76rem; }
.tbl th {
  font-size: 0.6rem; letter-spacing: 0.12em; text-transform: uppercase;
  color: var(--muted); font-weight: 500;
  text-align: left; padding: 5px 9px;
  border-bottom: 1px solid var(--line-2);
}
.tbl td { padding: 5px 9px; border-bottom: 1px solid var(--line); }
.tbl tbody tr { transition: background var(--fast); }
.tbl tbody tr:hover { background: var(--bg-2); }
.tbl .num { text-align: right; font-variant-numeric: tabular-nums; }

.count-num { font-variant-numeric: tabular-nums; }

/* tooltips ([data-tip]) — instant mono label */
[data-tip] { position: relative; }
[data-tip]::after {
  content: attr(data-tip);
  position: absolute; right: calc(100% + 8px); top: 50%;
  translate: 0 -50%;
  padding: 3px 8px;
  font-family: var(--mono); font-size: 0.64rem;
  color: var(--bg); white-space: nowrap;
  background: var(--ink);
  border: none;
  opacity: 0;
  pointer-events: none;
  transition: opacity var(--fast);
  z-index: 60;
}
[data-tip]:hover::after { opacity: 1; transition-delay: 350ms; }
