console: the lead file is a file again, and the journey is on the page
THE FILE WAS THIRTEEN TABS. One group of fields visible at a time, so "what do we know about this lead?" meant thirteen clicks and a good memory — on a page called the Lead FILE. A file you can read one page of at a time is a filing cabinet. Every group is now a card, laid out in columns that reflow to the width: three on a wide screen, two normally, one on a laptop. The whole 360 is one scroll and Ctrl-F finds anything. Groups avoid breaking across a column boundary — a heading at the foot of one column with its fields at the head of the next is worse than an uneven column — and inside a group the label/value pairs stack, so a long value is not squeezed into half a column against its label. THE JOURNEY IS AT THE TOP. The page named the current stage in a corner chip and said nothing about the path, so "how far along is this?" — the first question anyone asks — needed the workflow memorised. Passed steps are read from the AUDIT, not assumed from the order. A lead can skip (documents uploaded from Qualified carried one straight past Contacted) and can go backwards (a callback returns it to Awaiting Contact); colouring everything left of the current stage would claim steps that never happened. The side states — Parked, Referred, Lost, Declined — are deliberately off the rail: they are departures from the path, not points every lead passes, and a row implying otherwise would be a lie about the process. When the lead is in one, the rail names it at the end instead. THE TRAIL STOPS READING AS A MARGIN NOTE. 384px beside a full-width file made a column of two-line entries look like an aside; it is the half of the page that says what happened. Widened to 440. Layout only. The form, the actions, the audit fetch and every submission path are untouched. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
de8b158ca9
commit
3069bf4849
96
src/components/StageRail.css
Normal file
96
src/components/StageRail.css
Normal file
@ -0,0 +1,96 @@
|
|||||||
|
/* The journey, across the top. Eight steps have to fit without wrapping on a
|
||||||
|
laptop, so the labels are short and the dots carry the state. */
|
||||||
|
.rail {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 20px;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
padding: 16px 22px;
|
||||||
|
border-radius: var(--r-lg);
|
||||||
|
border: 1px solid var(--zk-line);
|
||||||
|
background: var(--zk-white);
|
||||||
|
}
|
||||||
|
|
||||||
|
.rail ol {
|
||||||
|
display: flex;
|
||||||
|
align-items: flex-start;
|
||||||
|
list-style: none;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
flex: 1;
|
||||||
|
min-width: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.rail__s {
|
||||||
|
position: relative;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
gap: 7px;
|
||||||
|
flex: 1;
|
||||||
|
min-width: 0;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.rail__dot {
|
||||||
|
width: 11px;
|
||||||
|
height: 11px;
|
||||||
|
border-radius: 50%;
|
||||||
|
flex: none;
|
||||||
|
background: var(--zk-white);
|
||||||
|
border: 2px solid var(--zk-line);
|
||||||
|
z-index: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.rail__l {
|
||||||
|
font-size: 0.72rem;
|
||||||
|
color: var(--zk-grey);
|
||||||
|
white-space: nowrap;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
max-width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* The connector sits behind the dots, drawn from each step to the next. */
|
||||||
|
.rail__bar {
|
||||||
|
position: absolute;
|
||||||
|
top: 4.5px;
|
||||||
|
left: 50%;
|
||||||
|
width: 100%;
|
||||||
|
height: 2px;
|
||||||
|
background: var(--zk-line-soft);
|
||||||
|
}
|
||||||
|
.rail__bar.is-done { background: var(--zk-blue-light); }
|
||||||
|
|
||||||
|
.is-done .rail__dot { background: var(--zk-blue-light); border-color: var(--zk-blue-light); }
|
||||||
|
.is-done .rail__l { color: var(--zk-muted); }
|
||||||
|
|
||||||
|
.is-here .rail__dot {
|
||||||
|
background: var(--zk-blue);
|
||||||
|
border-color: var(--zk-blue);
|
||||||
|
box-shadow: 0 0 0 4px rgba(33, 103, 174, 0.16);
|
||||||
|
}
|
||||||
|
.is-here .rail__l { color: var(--zk-blue-dark); font-weight: 600; }
|
||||||
|
|
||||||
|
/* Off the path — Parked, Referred, Lost, Declined. Named rather than drawn
|
||||||
|
into the row: these are departures, not points every lead passes. */
|
||||||
|
.rail__off {
|
||||||
|
flex: none;
|
||||||
|
font-size: 0.78rem;
|
||||||
|
color: var(--zk-amber-ink);
|
||||||
|
background: var(--zk-amber-tint);
|
||||||
|
border: 1px solid var(--zk-amber-line);
|
||||||
|
padding: 6px 14px;
|
||||||
|
border-radius: var(--r-pill);
|
||||||
|
}
|
||||||
|
.rail__off.is-closed {
|
||||||
|
color: var(--zk-muted);
|
||||||
|
background: var(--zk-tint);
|
||||||
|
border-color: var(--zk-line);
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 900px) {
|
||||||
|
.rail__l { display: none; }
|
||||||
|
.rail { padding: 14px 18px; }
|
||||||
|
}
|
||||||
81
src/components/StageRail.jsx
Normal file
81
src/components/StageRail.jsx
Normal file
@ -0,0 +1,81 @@
|
|||||||
|
import { STAGES } from '../api/config.js'
|
||||||
|
import './StageRail.css'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Where this lead has been, where it is, and what is left.
|
||||||
|
*
|
||||||
|
* The page said the stage in one chip in the corner and nothing about the
|
||||||
|
* journey, so "how far along is this?" — the first question anyone asks about
|
||||||
|
* a lead — could only be answered by knowing the workflow by heart.
|
||||||
|
*
|
||||||
|
* PASSED IS READ FROM THE AUDIT, NOT ASSUMED FROM THE ORDER. A lead can skip
|
||||||
|
* (documents uploaded from Qualified carried one straight past Contacted) and
|
||||||
|
* can go backwards (a callback returns it to Awaiting Contact). Colouring
|
||||||
|
* everything left of the current stage would have claimed steps that never
|
||||||
|
* happened. The trail knows which states this lead actually entered; this
|
||||||
|
* reads that.
|
||||||
|
*
|
||||||
|
* The side states — Parked, Referred, Lost, Declined — are deliberately NOT on
|
||||||
|
* the rail. They are departures from the path rather than points along it, and
|
||||||
|
* putting them in a row would suggest every lead passes through. When the lead
|
||||||
|
* is in one, the rail says so at the end instead.
|
||||||
|
*/
|
||||||
|
const PATH = [
|
||||||
|
'zk-state-new', 'zk-state-qualified', 'zk-state-contacted', 'zk-state-docs',
|
||||||
|
'zk-state-quoted', 'zk-state-payment', 'zk-state-issued', 'zk-state-onboarded',
|
||||||
|
]
|
||||||
|
|
||||||
|
/** Short enough to fit eight across; the queue names are written for a sidebar. */
|
||||||
|
const SHORT = {
|
||||||
|
'zk-state-new': 'Filed',
|
||||||
|
'zk-state-qualified': 'Called',
|
||||||
|
'zk-state-contacted': 'Contacted',
|
||||||
|
'zk-state-docs': 'Documents',
|
||||||
|
'zk-state-quoted': 'Quoted',
|
||||||
|
'zk-state-payment': 'Payment',
|
||||||
|
'zk-state-issued': 'Issued',
|
||||||
|
'zk-state-onboarded': 'Onboarded',
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function StageRail({ audit, currentName }) {
|
||||||
|
const current = STAGES.find((s) => s.name === currentName)
|
||||||
|
const visited = new Set(
|
||||||
|
(audit || [])
|
||||||
|
.map((r) => r.execution_state)
|
||||||
|
.filter((v) => PATH.includes(v)),
|
||||||
|
)
|
||||||
|
if (current) visited.add(current.uid)
|
||||||
|
|
||||||
|
const currentIndex = PATH.indexOf(current?.uid)
|
||||||
|
// A lead sitting somewhere off the path — Parked, Referred, Lost, Declined.
|
||||||
|
const aside = current && currentIndex === -1 ? current : null
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="rail" aria-label="Progress">
|
||||||
|
<ol>
|
||||||
|
{PATH.map((uid, i) => {
|
||||||
|
const been = visited.has(uid)
|
||||||
|
const here = uid === current?.uid
|
||||||
|
// Ahead of a lead that has left the path is unknowable — a referred
|
||||||
|
// risk may never see payment — so nothing after it is called "to do".
|
||||||
|
const state = here ? 'here' : been ? 'done' : 'todo'
|
||||||
|
return (
|
||||||
|
<li key={uid} className={'rail__s is-' + state}>
|
||||||
|
<span className="rail__dot" aria-hidden="true" />
|
||||||
|
<span className="rail__l">{SHORT[uid]}</span>
|
||||||
|
{i < PATH.length - 1 ? (
|
||||||
|
<span className={'rail__bar' + (visited.has(PATH[i + 1]) ? ' is-done' : '')} aria-hidden="true" />
|
||||||
|
) : null}
|
||||||
|
</li>
|
||||||
|
)
|
||||||
|
})}
|
||||||
|
</ol>
|
||||||
|
|
||||||
|
{aside ? (
|
||||||
|
<div className={'rail__off' + (aside.kind === 'end' ? ' is-closed' : '')}>
|
||||||
|
{aside.kind === 'end' ? 'Ended in' : 'Now in'} <strong>{aside.name}</strong>
|
||||||
|
</div>
|
||||||
|
) : null}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
@ -7,6 +7,7 @@ import AgentChip from '../components/AgentChip.jsx'
|
|||||||
import CallTranscript from '../components/CallTranscript.jsx'
|
import CallTranscript from '../components/CallTranscript.jsx'
|
||||||
import ClampText from '../components/ClampText.jsx'
|
import ClampText from '../components/ClampText.jsx'
|
||||||
import Conversation from '../components/Conversation.jsx'
|
import Conversation from '../components/Conversation.jsx'
|
||||||
|
import StageRail from '../components/StageRail.jsx'
|
||||||
import Timeline from '../components/Timeline.jsx'
|
import Timeline from '../components/Timeline.jsx'
|
||||||
import { APP_ID, DV_LEAD, PRODUCTS, STAGES, STALL_AFTER_MS, blockedOn, nudgeFor, phaseOf } from '../api/config.js'
|
import { APP_ID, DV_LEAD, PRODUCTS, STAGES, STALL_AFTER_MS, blockedOn, nudgeFor, phaseOf } from '../api/config.js'
|
||||||
import { AGENTS } from '../api/agents.js'
|
import { AGENTS } from '../api/agents.js'
|
||||||
@ -143,7 +144,6 @@ export default function Lead() {
|
|||||||
const [row, setRow] = useState(null)
|
const [row, setRow] = useState(null)
|
||||||
const [err, setErr] = useState(null)
|
const [err, setErr] = useState(null)
|
||||||
const [open, setOpen] = useState(null)
|
const [open, setOpen] = useState(null)
|
||||||
const [tab, setTab] = useState(0)
|
|
||||||
const [labels, setLabels] = useState({})
|
const [labels, setLabels] = useState({})
|
||||||
// The audit rows live HERE, not inside Timeline, for two reasons: Timeline
|
// The audit rows live HERE, not inside Timeline, for two reasons: Timeline
|
||||||
// fetched them once on mount and never again — so a lead worked by five
|
// fetched them once on mount and never again — so a lead worked by five
|
||||||
@ -249,7 +249,6 @@ export default function Lead() {
|
|||||||
keys.map((k) => [k, fmt(k, row[k]), filesOf(row[k])]).filter(([, v]) => v !== null),
|
keys.map((k) => [k, fmt(k, row[k]), filesOf(row[k])]).filter(([, v]) => v !== null),
|
||||||
])
|
])
|
||||||
.filter(([, shown]) => shown.length)
|
.filter(([, shown]) => shown.length)
|
||||||
const active = Math.min(tab, Math.max(groups.length - 1, 0))
|
|
||||||
|
|
||||||
const stateName = row.current_state_name || ''
|
const stateName = row.current_state_name || ''
|
||||||
// The state, then what is really happening inside it — see phaseOf. Actions
|
// The state, then what is really happening inside it — see phaseOf. Actions
|
||||||
@ -391,6 +390,8 @@ export default function Lead() {
|
|||||||
)
|
)
|
||||||
})()}
|
})()}
|
||||||
|
|
||||||
|
<StageRail audit={audit} currentName={stateName} />
|
||||||
|
|
||||||
<div className="lead">
|
<div className="lead">
|
||||||
<div className="lead__main">
|
<div className="lead__main">
|
||||||
{note ? (
|
{note ? (
|
||||||
@ -608,34 +609,37 @@ export default function Lead() {
|
|||||||
)
|
)
|
||||||
})()}
|
})()}
|
||||||
|
|
||||||
{/* The flow's own detail. Each group is one click away rather than one
|
{/* EVERYTHING AT ONCE.
|
||||||
long scroll, and prose is folded to a few lines — the page can be
|
This was tabs — thirteen of them, one group visible at a time —
|
||||||
scanned, and still holds everything for whoever wants it. */}
|
so "what do we know about this lead?" meant clicking thirteen
|
||||||
|
times and holding the answer in your head. It is a lead FILE; a
|
||||||
|
file you can only read one page of is a filing cabinet.
|
||||||
|
Now every group is a card, laid out in columns that reflow, so
|
||||||
|
the whole 360 is one scroll and Ctrl-F finds anything. */}
|
||||||
{groups.length ? (
|
{groups.length ? (
|
||||||
<div className="panel">
|
<div className="panel">
|
||||||
<div className="panel__head">
|
<div className="panel__head">
|
||||||
<div>
|
<div>
|
||||||
<h2 className="panel__title">Lead file</h2>
|
<h2 className="panel__title">Lead file</h2>
|
||||||
<p className="panel__sub">Everything captured, grouped by the step that captured it.</p>
|
<p className="panel__sub">
|
||||||
|
Everything captured, grouped by the step that captured it.
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
<span className="panel__meta">
|
||||||
|
{groups.reduce((n, [, shown]) => n + shown.length, 0)} fields
|
||||||
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div className="tabs" role="tablist">
|
|
||||||
{groups.map(([title, shown], i) => (
|
<div className="file360">
|
||||||
<button
|
{groups.map(([title, shown]) => (
|
||||||
key={title} type="button" role="tab" aria-selected={i === active}
|
<section className="fgroup" key={title}>
|
||||||
className={'tab' + (i === active ? ' is-on' : '')}
|
<h3>{title}<span>{shown.length}</span></h3>
|
||||||
onClick={() => setTab(i)}
|
|
||||||
>
|
|
||||||
{title}<span className="tab__n">{shown.length}</span>
|
|
||||||
</button>
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
<dl className="props">
|
<dl className="props">
|
||||||
{groups[active][1].map(([k, v, files]) => (
|
{shown.map(([k, v, files]) => (
|
||||||
files.length ? (
|
files.length ? (
|
||||||
/* An attached document is a thing to open, not a filename
|
/* An attached document is a thing to open, not a
|
||||||
to read. The preview route is app-scoped and public, so
|
filename to read. The preview route is app-scoped
|
||||||
a plain link works with no token plumbing. */
|
and public, so a plain link needs no token. */
|
||||||
<div className="prop" key={k}>
|
<div className="prop" key={k}>
|
||||||
<dt>{labels[k] ?? label(k)}</dt>
|
<dt>{labels[k] ?? label(k)}</dt>
|
||||||
<dd className="prop__files">
|
<dd className="prop__files">
|
||||||
@ -664,6 +668,9 @@ export default function Lead() {
|
|||||||
)
|
)
|
||||||
))}
|
))}
|
||||||
</dl>
|
</dl>
|
||||||
|
</section>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
) : null}
|
) : null}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -588,7 +588,10 @@
|
|||||||
/* ---- lead: the file beside the story ---- */
|
/* ---- lead: the file beside the story ---- */
|
||||||
.lead {
|
.lead {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: minmax(0, 1fr) 384px;
|
/* Wider than it was. At 384px the trail was a column of two-line entries
|
||||||
|
beside a full-width file, which read as a margin note rather than as the
|
||||||
|
other half of the page — and it is the half that says what happened. */
|
||||||
|
grid-template-columns: minmax(0, 1fr) 440px;
|
||||||
gap: 20px;
|
gap: 20px;
|
||||||
align-items: start;
|
align-items: start;
|
||||||
}
|
}
|
||||||
@ -616,7 +619,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.lead__feed {
|
.lead__feed {
|
||||||
max-height: calc(100vh - 210px);
|
max-height: calc(100vh - 240px);
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
overscroll-behavior: contain;
|
overscroll-behavior: contain;
|
||||||
padding: 0 22px 20px;
|
padding: 0 22px 20px;
|
||||||
@ -642,62 +645,6 @@
|
|||||||
what a tab is for; a pill segment reads as a filter on shared content. The
|
what a tab is for; a pill segment reads as a filter on shared content. The
|
||||||
2px rule lives on the button, so a strip that wraps to two rows still marks
|
2px rule lives on the button, so a strip that wraps to two rows still marks
|
||||||
the active one correctly. */
|
the active one correctly. */
|
||||||
.tabs {
|
|
||||||
display: flex;
|
|
||||||
flex-wrap: wrap;
|
|
||||||
gap: 2px;
|
|
||||||
margin-bottom: 20px;
|
|
||||||
border-bottom: 1px solid var(--zk-line);
|
|
||||||
}
|
|
||||||
|
|
||||||
.tab {
|
|
||||||
font: inherit;
|
|
||||||
font-size: 0.82rem;
|
|
||||||
white-space: nowrap;
|
|
||||||
cursor: pointer;
|
|
||||||
display: inline-flex;
|
|
||||||
align-items: center;
|
|
||||||
gap: 7px;
|
|
||||||
padding: 9px 13px;
|
|
||||||
background: none;
|
|
||||||
border: 0;
|
|
||||||
border-bottom: 2px solid transparent;
|
|
||||||
border-radius: var(--r-sm) var(--r-sm) 0 0;
|
|
||||||
color: var(--zk-muted);
|
|
||||||
transition: color var(--t-fast), background var(--t-fast), border-color var(--t-fast);
|
|
||||||
}
|
|
||||||
|
|
||||||
.tab:hover {
|
|
||||||
background: var(--zk-tint);
|
|
||||||
color: var(--zk-ink);
|
|
||||||
}
|
|
||||||
|
|
||||||
.tab.is-on {
|
|
||||||
color: var(--zk-blue-dark);
|
|
||||||
font-weight: 500;
|
|
||||||
border-bottom-color: var(--zk-blue);
|
|
||||||
}
|
|
||||||
|
|
||||||
.tab__n {
|
|
||||||
font-size: 0.66rem;
|
|
||||||
font-variant-numeric: tabular-nums;
|
|
||||||
min-width: 18px;
|
|
||||||
padding: 1px 6px;
|
|
||||||
border-radius: var(--r-pill);
|
|
||||||
background: var(--zk-line-soft);
|
|
||||||
color: var(--zk-muted);
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.tab.is-on .tab__n {
|
|
||||||
background: var(--zk-tint-blue);
|
|
||||||
color: var(--zk-blue);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ---- property rows ----
|
|
||||||
Facts read as label/value pairs on hairlines rather than as a wall of filled
|
|
||||||
boxes: the tint was carrying no information and made every field shout as
|
|
||||||
loudly as every other. */
|
|
||||||
.props {
|
.props {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
display: grid;
|
display: grid;
|
||||||
@ -1415,3 +1362,65 @@
|
|||||||
.newlead svg { width: 14px; height: 14px; }
|
.newlead svg { width: 14px; height: 14px; }
|
||||||
.newlead:hover { background: var(--grad-blue-hover); box-shadow: var(--sh-md); transform: translateY(-1px); }
|
.newlead:hover { background: var(--grad-blue-hover); box-shadow: var(--sh-md); transform: translateY(-1px); }
|
||||||
.newlead:focus-visible { outline: 2px solid var(--zk-blue); outline-offset: 2px; }
|
.newlead:focus-visible { outline: 2px solid var(--zk-blue); outline-offset: 2px; }
|
||||||
|
|
||||||
|
/* ── the lead file, all of it ─────────────────────────────────────────────
|
||||||
|
This was thirteen tabs with one group visible at a time, so "what do we
|
||||||
|
know about this lead?" took thirteen clicks and a good memory. Columns
|
||||||
|
rather than a single list because most groups are three or four fields and
|
||||||
|
a stacked list of thirteen short groups is a very long page of white space.
|
||||||
|
`break-inside: avoid` keeps a group whole rather than split across a column
|
||||||
|
boundary — a heading at the foot of one column with its fields at the head
|
||||||
|
of the next is worse than an uneven column. */
|
||||||
|
.file360 {
|
||||||
|
padding: 4px 22px 20px;
|
||||||
|
columns: 2;
|
||||||
|
column-gap: 26px;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (min-width: 1500px) { .file360 { columns: 3; } }
|
||||||
|
@media (max-width: 1000px) { .file360 { columns: 1; } }
|
||||||
|
|
||||||
|
.fgroup {
|
||||||
|
break-inside: avoid;
|
||||||
|
display: inline-block;
|
||||||
|
width: 100%;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fgroup h3 {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
margin: 0 0 8px;
|
||||||
|
padding-bottom: 6px;
|
||||||
|
border-bottom: 1px solid var(--zk-line-soft);
|
||||||
|
font-size: 0.66rem;
|
||||||
|
font-weight: 600;
|
||||||
|
letter-spacing: 0.1em;
|
||||||
|
text-transform: uppercase;
|
||||||
|
color: var(--zk-blue-dark);
|
||||||
|
}
|
||||||
|
|
||||||
|
.fgroup h3 span {
|
||||||
|
font-size: 0.64rem;
|
||||||
|
font-weight: 500;
|
||||||
|
letter-spacing: 0;
|
||||||
|
color: var(--zk-grey);
|
||||||
|
background: var(--zk-tint);
|
||||||
|
border-radius: var(--r-pill);
|
||||||
|
padding: 1px 7px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Inside a group the pairs stack, so a long value is not squeezed into a
|
||||||
|
half-width column against a label. */
|
||||||
|
.file360 .props { display: block; padding: 0; }
|
||||||
|
.file360 .prop { padding: 5px 0; border: 0; }
|
||||||
|
.file360 .prop dt { font-size: 0.7rem; color: var(--zk-grey); margin-bottom: 1px; }
|
||||||
|
.file360 .prop dd { margin: 0; font-size: 0.84rem; color: var(--zk-ink); overflow-wrap: anywhere; }
|
||||||
|
|
||||||
|
.panel__meta {
|
||||||
|
flex: none;
|
||||||
|
font-size: 0.74rem;
|
||||||
|
color: var(--zk-grey);
|
||||||
|
font-variant-numeric: tabular-nums;
|
||||||
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user