/* ============================================================
   Ticketbot app layer — rules that are specific to this app and
   do not belong in ui.css (the design system). Tokens only, no
   literal colours or spacing. A rule that turns out to be a
   reusable component moves to ui.css.
   ============================================================ */

/* Screens the app shows and hides imperatively (auth vs. app shell,
   inline error slots, popovers). ui.css styles [hidden]; the app toggles
   a class, so the class needs the same behaviour. */
.hidden { display: none !important; }

/* An inline link inside body copy or a table cell. ui.css resets anchors to
   inherit, which is right for nav and rows; these are real links. */
.link { color: var(--accent-on-soft); font-weight: 500; }
.link:hover { text-decoration: underline; }

/* Table rows that open a detail page on click. */
.tbl tbody tr.clickable { cursor: pointer; }

/* Long free text in a dense row: ellipsis rather than a wrapped cell. */
.cell-ellipsis { max-width: 48ch; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* Monospace editing surfaces: condition text, patch ops, message templates. */
.textarea.mono {
    font-family: var(--font-mono);
    font-size: var(--text-xs);
    line-height: 1.6;
}

/* a link that leaves the app says so with a small trailing icon instead of a tooltip, because a
   tooltip inside the tickets table's scrolling wrap is clipped at the edge */
.link.ext { display: inline-flex; align-items: center; gap: var(--s1); }
.link.ext svg { width: 12px; height: 12px; stroke-width: 2; opacity: .7; }
/* The sidebar's Documentation entry opens a new tab; the same small trailing icon says so. */
.nav-item svg.nav-ext { width: 13px; height: 13px; margin-left: auto; color: var(--muted); }
.app.collapsed .nav-item svg.nav-ext { opacity: 0; }
/* Placeholder tokens under a message template — click to insert. */
.placeholder-list { display: flex; flex-wrap: wrap; gap: var(--s1); }
.placeholder-list .code { cursor: pointer; }
.placeholder-list .code:hover { border-color: var(--accent-line); color: var(--accent-on-soft); }

/* The "custom message" disclosure inside a notify action. */
.action-msg summary { cursor: pointer; user-select: none; }

/* Free text from ConnectWise (note previews, diff values, rendered messages) carries long
   unbroken tokens such as inline-image URLs. pre-wrap alone leaves those on one line, and
   on a phone that line runs past the viewport and gives the whole page a horizontal scroll. */
.note-text, .event-detail, .diff-table td { overflow-wrap: anywhere; }

/* A code block that wraps instead of scrolling: compiled conditions and simulated messages
   are read in full, not scanned horizontally. */
.code.prewrap { white-space: pre-wrap; overflow-wrap: anywhere; }

/* "or" divider between "Sign in with Microsoft" and the password form on the login card. ui.css
   has no divider component; this is a hairline either side of a muted eyebrow word. */
.auth-or {
    display: flex; align-items: center; gap: var(--s3);
    color: var(--muted); font-size: var(--text-xs); text-transform: uppercase; letter-spacing: .06em;
}
.auth-or::before, .auth-or::after { content: ''; flex: 1; border-top: 1px solid var(--line); }

/* Numbered setup steps on the SSO page. ui.css resets list markers globally; these are read in
   order, so the numbers matter. */
.steps { list-style: decimal; padding-left: var(--s6); }
.steps li::marker { color: var(--muted); }

/* The editor is one column the height of the view, so the canvas takes whatever
   the toolbar (and the dry-run banner, when it is up) leaves instead of a magic
   constant that only holds for one of them. The floor keeps it usable on a short
   window; past that the page scrolls, as it always did. */
.wf-page {
    display: flex; flex-direction: column;
    height: calc(100vh - var(--topbar-h) - var(--s8) - var(--s12));
}
/* the tab strip and canvas share the page's height: the frame takes it, the canvas the rest */
.wf-page .cv-frame { flex: 1; }
.wf-canvas { flex: 1; min-height: 480px; }
/* the results page shows the canvas above the run's events, so it takes a fixed height instead of the view */
.run-canvas { flex: none; height: 460px; min-height: 0; }
/* the step list is narrow: names and swatches only */
.wf-canvas .dock-l { width: 190px; }
.wf-canvas .dock-r { width: 330px; }
/* both docks stop above the HUD row so the zoom cluster never sits under a panel */
.wf-canvas .dock { bottom: 46px; }
/* the inspector's card head is compact: the panel is narrow and the kind label is short */
.wf-canvas .dock .card-head { padding: var(--s3) var(--s4); }
.wf-canvas .dock .card-body { padding: 0 var(--s4) var(--s4); }
/* the simulation trace reuses the ticket-history event rail inside the dock */
.wf-canvas .dock .events { padding-left: var(--s5); }
/* the toolbar above the canvas is a bare row, not a card's toolbar */
.wf-toolbar { padding: 0; margin-bottom: var(--s3); }
/* the name starts narrow so the whole toolbar fits one row at 1280px, and grows when there is room */
.wf-toolbar .input.wf-name { flex: 1 1 112px; min-width: 112px; max-width: 240px; }
/* the toolbar wraps in groups (simulate, then results/help/save); the save group keeps to the right */
.wf-toolbar-end { margin-left: auto; position: relative; }
/* the unsaved dot sits on Save's corner, so showing it never reflows the toolbar */
.wf-toolbar-end #wf-dirty { position: absolute; top: -3px; right: -3px; z-index: 1; }
.wf-toolbar .input.wf-ticket { width: 92px; }
/* a list's "Used by" banner holds a row of workflow buttons: they sit after the label, not
   pushed to the banner's end like a banner's single action */
.banner .used-by .btn { margin-left: 0; }
/* a sync phase's errors have no timestamp, so the log row drops its time column */
.sync-errors .log-row { grid-template-columns: 54px 1fr; }
/* "Load older events" sits at the ticket history's old end, above or below the rail, lined up with the cards */
.tk-older { margin: var(--s3) 0 var(--s3) var(--s6); }

/* AI page (ai.js). Stat tiles there carry no sparkline, so they drop the room .stat keeps for
   one; the tile rows are five and six wide, which the .g* grids do not offer. */
.ai-stat { padding-bottom: var(--s5); }
/* an agent's results page: the range picker sits above the tiles it drives */
.ai-range { margin-bottom: var(--s4); }
/* the metrics budget line sits under the range filter bar and lines up with it; the spend stack
   takes the row and the alert note wraps under it on a narrow screen */
.ai-budget { padding: var(--s4); align-items: center; }
.ai-budget > .stack { flex: 1 1 280px; }
.ai-tiles-5 { grid-template-columns: repeat(5, minmax(0, 1fr)); }
.ai-tiles-6 { grid-template-columns: repeat(6, minmax(0, 1fr)); }
@media (max-width: 1100px) { .ai-tiles-5, .ai-tiles-6 { grid-template-columns: repeat(3, minmax(0, 1fr)); } }
@media (max-width: 640px) { .ai-tiles-5, .ai-tiles-6 { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
/* result cells: a proposal and a ticket summary cut off with the full text on hover, so the
   nine result columns fit a laptop-width card */
.tbl:not(.is-sized) .ai-summary { max-width: 10ch; }
.tbl:not(.is-sized) .ai-proposal { max-width: 15ch; }
/* once a column has been resized the cell follows its width instead */
.tbl.is-sized .ai-summary, .tbl.is-sized .ai-proposal { max-width: none; }
/* Tickets table (tickets.js TK_COLUMNS): text columns are capped one line each so the table fits a
   laptop-width card; a resized column drops the cap */
.tbl:not(.is-sized) .tk-summary { max-width: 28ch; }
.tbl:not(.is-sized) .tk-status { max-width: 17ch; }
.tbl:not(.is-sized) .tk-company { max-width: 16ch; }
.tbl:not(.is-sized) .tk-owner { max-width: 16ch; }
.ai-reason { font-size: var(--text-sm); color: var(--ink-2); max-width: 90ch; }
.ai-legend { display: flex; flex-wrap: wrap; gap: var(--s4); font-size: var(--text-xs); color: var(--muted); }
.ai-legend i { display: inline-block; width: 8px; height: 8px; border-radius: var(--radius-sm); margin-right: var(--s1); }
.ai-combos { margin-top: var(--s3); font-size: var(--text-sm); }
/* one output field in a custom-fields agent's setup: its own bordered block so the name, type,
   options and description read as one field among several */
.ai-field-edit { border: 1px solid var(--line); border-radius: var(--radius); padding: var(--s3); }
/* feedback: thumbs counts on a result row, the rating controls and others' ratings when it opens */
.ai-fb { display: inline-flex; gap: var(--s2); font-size: var(--text-xs); color: var(--ink-2); }
.ai-fb > span, .ai-fb-entry > span { display: inline-flex; align-items: center; gap: 2px; }
.ai-fb svg, .ai-fb-entry > span svg { width: 13px; height: 13px; }
.ai-fb-up svg { color: var(--ok); }
.ai-fb-down svg { color: var(--bad); }
/* the row's feedback button holds the counts; the modal's Good / Bad toggle has an icon beside
   each label rather than above it */
.ai-fb-btn { padding: 0 var(--s1); }
.ai-fb-seg button { display: inline-flex; align-items: center; gap: var(--s1); }
.ai-fb-seg button svg { width: 14px; height: 14px; }
.ai-fb-entry { display: flex; gap: var(--s2); align-items: flex-start; font-size: var(--text-sm); }
.ai-combos ul { margin-top: var(--s2); columns: 2; column-gap: var(--s6); color: var(--ink-2); }

/* Editor canvas dock (workflows.js cvCanvasHTML): the arrange tools sit after the zoom
   controls behind a divider; the undo slot is empty until an arrange can be undone. */
.dock-bar > .cv-dock-sep { width: 1px; height: var(--s4); padding: 0; margin: 0 var(--s1); background: var(--line); }
.dock-bar > .cv-dock-slot { display: contents; }
/* On a narrow screen the canvas hint bar has no room and covers the cards, and the inspector
   takes the whole canvas above the corner controls so they never sit on top of it. */
@media (max-width: 860px) {
  .wf-canvas #cv-hint { display: none; }
  .wf-canvas .dock-r { z-index: 8; left: var(--s3); bottom: var(--s3); width: auto; }
}

/* Settings page (app.js renderConfig): the settings run several screens long, so the head with
   Save sticks under the topbar. */
.config-head {
  position: sticky; top: var(--topbar-h); z-index: 20;
  margin: calc(-1 * var(--s3)) 0 var(--s3); padding: var(--s3) 0;
  background: var(--bg); border-bottom: 1px solid var(--line-soft);
}
/* the canvas hint bar is a line of text with keycaps in it: pad the text, not each keycap group */
.wf-canvas #cv-hint { padding: 3px var(--s3); }
.wf-canvas #cv-hint > .keys { padding: 0; margin: 0 var(--s1); }
/* a long command in a .secret row wraps at any character instead of pushing the copy button out */
.secret .secret-text { flex: 1; min-width: 0; overflow-wrap: anywhere; }
