You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
dianshang-qianduan/src/views/product/after-sales-service.vue

229 lines
25 KiB
Vue

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

<template>
<div class="after-sales-page student-training-shell">
<main class="training-core">
<section class="task-header">
<div class="task-badge"><el-icon><Service /></el-icon> · </div>
<h1 class="task-title">{{ taskTitle }}</h1>
</section>
<TrainingTaskBrief :background="taskBackground" :goals="taskGoals" :requirements="taskRequirement" :show-material="false" />
<section class="task-card">
<div class="workbench-head workbench-head--actions-only">
<div class="workbench-actions">
<TrainingMaterialButton :material-name="taskConfig?.materialName" :material-url="taskConfig?.materialUrl" />
<button type="button" class="outline-action" @click="exportOutcome"><el-icon><Download /></el-icon></button>
</div>
</div>
<nav v-if="hasConfiguredSteps" class="step-indicator" aria-label="售后服务流程设计步骤">
<template v-for="(step, index) in configuredSteps" :key="`${step}-${index}`">
<button
type="button"
:class="['step-tab', { active: activeStep === index + 1, complete: activeStep > index + 1 }]"
:aria-current="activeStep === index + 1 ? 'step' : undefined"
:aria-label="`第${index + 1}步:${step}`"
@click="setCurrentStep(index + 1)"
>
<span class="step-marker">{{ String(index + 1).padStart(2, '0') }}</span>
<span class="step-copy">
<strong class="step-name" :title="step">{{ step }}</strong>
<span class="step-action">{{ activeStep === index + 1 ? "当前步骤" : "点击切换" }} <span aria-hidden="true"></span></span>
</span>
</button>
<span v-if="index < configuredSteps.length - 1" class="step-connector" aria-hidden="true"></span>
</template>
</nav>
<section v-show="isSectionVisible(1)" class="step-card">
<StepHeading :step="activeStep" :title="activeStepName" />
<div class="step-content">
<h4>售后服务闭环</h4>
<p>售后服务并非单次响应,而是从用户问题进入、问题识别、责任分流、解决交付、回访评价到问题沉淀的完整闭环。设计时应优先保证入口清晰、响应可预期、升级有边界、结果可追踪。</p>
<div class="service-flow" aria-label="售后服务闭环示意">
<article v-for="item in serviceFlow" :key="item.title"><strong>{{ item.title }}</strong><span>{{ item.description }}</span></article>
</div>
<div class="hint-card"><strong>填写提示:</strong>先明确产品和典型售后场景,再定义每类问题的处理时效与责任角色,最后补全回访和产品改进机制。</div>
</div>
</section>
<section v-show="isSectionVisible(2)" class="step-card">
<StepHeading :step="activeStep" :title="activeStepName" />
<div class="step-content">
<label class="field-block"><span>产品名称</span><el-input v-model="form.productName" placeholder="填写智能产品名称" /></label>
<label class="field-block"><span>服务场景</span><el-input v-model="form.serviceScenario" type="textarea" :autosize="{ minRows: 7, maxRows: 10 }" placeholder="列出安装、联网、使用、故障、退换货等典型售后场景" /></label>
</div>
</section>
<section v-show="isSectionVisible(3)" class="step-card">
<StepHeading :step="activeStep" :title="activeStepName" />
<div class="step-content">
<label class="field-block"><span>服务标准</span><el-input v-model="form.serviceSla" type="textarea" :autosize="{ minRows: 6, maxRows: 9 }" placeholder="说明响应时间、处理时限、升级规则和责任角色" /></label>
<div class="table-panel">
<div class="panel-title"><h4>售后流程设计表</h4><p>为每一项写明学生设计的服务规则或动作。</p></div>
<div class="table-wrap">
<table>
<thead><tr><th>项目</th><th>说明</th><th>学生填写</th></tr></thead>
<tbody><tr v-for="row in workRows" :key="row.name"><th scope="row">{{ row.name }}</th><td>{{ row.description }}</td><td><el-input v-model="row.answer" type="textarea" :autosize="{ minRows: 3, maxRows: 6 }" placeholder="填写本项分析内容" /></td></tr></tbody>
</table>
</div>
</div>
</div>
</section>
<section v-show="isSectionVisible(4)" class="step-card">
<StepHeading :step="activeStep" :title="activeStepName" />
<div class="step-content">
<label class="field-block"><span>闭环机制</span><el-input v-model="form.serviceLoop" type="textarea" :autosize="{ minRows: 8, maxRows: 12 }" placeholder="说明回访、评价、问题复盘和产品改进沉淀方式" /></label>
<div class="hint-card"><strong>成果检查:</strong>确认服务入口、问题分类、处理动作、时效标准和数据沉淀均已填写,且能够对应到真实的用户服务场景。</div>
</div>
</section>
<section v-show="hasConfiguredSteps && activeStep > 4" class="step-card">
<StepHeading :step="activeStep" :title="activeStepName" />
<p class="step-desc">请检查前述服务流程与成果填写是否完整,再保存或提交实训成果。</p>
</section>
<div v-if="hasConfiguredSteps" class="step-navigation">
<button type="button" class="btn-nav" :disabled="activeStep === 1" @click="goPreviousStep"><el-icon><ArrowLeft /></el-icon>上一步</button>
<button type="button" class="btn-nav btn-save" :disabled="saving" @click="saveCurrentProgress"><el-icon><CircleCheck /></el-icon>保存当前进度</button>
<button type="button" class="btn-nav btn-primary" :disabled="activeStep === configuredSteps.length" @click="goNextStep">下一步<el-icon><ArrowRight /></el-icon></button>
</div>
<div class="training-actions">
<el-button class="training-action training-action--submit" :loading="saving" @click="submitTask">提交任务</el-button>
<el-button class="training-action training-action--reset" :loading="saving" @click="resetTask">清空填写</el-button>
</div>
</section>
</main>
<TrainingAiSidebar
study-tip="当前任务建议:从用户问题入口开始,设计可分流、可升级、可追踪的售后服务闭环。"
reference-title="售后流程设计要点"
reference-text="· 入口明确电话、在线客服、App、门店或工单系统<br />· 分流清晰:硬件、软件、网络、使用指导、退换货<br />· 闭环沉淀:回访评价、高频问题复盘、产品持续改进"
:progress-items="progressItems"
/>
</div>
</template>
<script setup>
import { computed, defineComponent, getCurrentInstance, h, onMounted, ref } from "vue";
import { ArrowLeft, ArrowRight, CircleCheck, Download, Service } from "@element-plus/icons-vue";
import TrainingAiSidebar from "@/views/components/TrainingAiSidebar.vue";
import TrainingMaterialButton from "@/views/components/TrainingMaterialButton.vue";
import TrainingTaskBrief from "@/views/components/TrainingTaskBrief.vue";
import { getTrainingTaskByKey } from "@/api/trainingTask";
import { getStudentTrainingAnswer, saveStudentTrainingAnswer } from "@/api/studentTrainingAnswer";
import { getStudentTrainingPage } from "@/views/training/studentTrainingPages";
import { parseTrainingArray } from "@/views/training/taskKeyMap";
const TASK_KEY = "after-sales-service";
const { proxy } = getCurrentInstance();
const basePage = getStudentTrainingPage(TASK_KEY);
const taskConfig = ref(null);
const saving = ref(false);
const activeStep = ref(1);
const form = ref(createForm());
const workRows = ref(createRows());
const taskTitle = computed(() => taskConfig.value?.taskName || basePage.title);
const taskBackground = computed(() => taskConfig.value?.background || basePage.background);
const taskRequirement = computed(() => taskConfig.value?.requirements || basePage.task);
const taskGoals = computed(() => parseTrainingArray(taskConfig.value?.objectives, basePage.goals));
const configuredSteps = computed(() => parseTrainingArray(taskConfig.value?.steps));
const hasConfiguredSteps = computed(() => configuredSteps.value.length > 0);
const activeStepName = computed(() => configuredSteps.value[activeStep.value - 1] || "售后服务流程设计");
const progressItems = computed(() => configuredSteps.value.map((text, index) => ({ text, status: index + 1 < activeStep.value ? "done" : index + 1 === activeStep.value ? "doing" : "" })));
const serviceFlow = [
{ title: "问题受理", description: "统一入口与工单记录" },
{ title: "诊断分流", description: "按问题类型明确责任" },
{ title: "解决交付", description: "远程、维修或换新处理" },
{ title: "回访沉淀", description: "评价复盘并反哺产品" },
];
const StepHeading = defineComponent({
props: { step: { type: Number, required: true }, title: { type: String, required: true } },
setup(props) {
return () => h("div", { class: "step-title-row" }, [h("div", [h("p", { class: "section-eyebrow" }, `Step ${String(props.step).padStart(2, "0")}`), h("h3", props.title)])]);
},
});
function createForm() { return { productName: "", serviceScenario: "", serviceSla: "", serviceLoop: "" }; }
function createRows() { return (basePage.tableRows || []).map(([name, description]) => ({ name, description, answer: "" })); }
function normalizeActiveStep(value) { if (!configuredSteps.value.length) return 1; return Math.min(Math.max(Number(value) || 1, 1), configuredSteps.value.length); }
function isSectionVisible(section) { return !hasConfiguredSteps.value || activeStep.value === section; }
onMounted(async () => { await loadTaskConfig(); await loadSavedProgress(); });
async function loadTaskConfig() {
try { const res = await getTrainingTaskByKey(TASK_KEY); taskConfig.value = res?.data || null; activeStep.value = normalizeActiveStep(activeStep.value); }
catch (error) { taskConfig.value = null; activeStep.value = 1; }
}
function buildProgress() { return { activeStep: activeStep.value, form: form.value, workRows: workRows.value, updatedAt: new Date().toISOString() }; }
function applyProgress(value) {
if (!value || typeof value !== "object") return;
activeStep.value = normalizeActiveStep(value.activeStep);
form.value = { ...createForm(), ...(value.form || {}) };
workRows.value = createRows().map((row, index) => ({ ...row, answer: value.workRows?.[index]?.answer || "" }));
}
async function loadSavedProgress() {
try { const res = await getStudentTrainingAnswer(TASK_KEY); const raw = res?.data?.step1Answer; if (raw) applyProgress(JSON.parse(raw)); }
catch (error) { /* Keep the task usable when historical answers are unavailable. */ }
}
async function persistProgress(saveAction = "SAVE", silent = false) {
await saveStudentTrainingAnswer(TASK_KEY, { saveAction, currentStep: activeStep.value, step1Answer: JSON.stringify(buildProgress()) });
if (!silent) proxy?.$modal?.msgSuccess(saveAction === "SUBMIT" ? "提交成功" : "保存成功");
}
function setCurrentStep(step) { activeStep.value = normalizeActiveStep(step); persistProgress("SAVE", true).catch(() => {}); }
function goPreviousStep() { setCurrentStep(activeStep.value - 1); }
function goNextStep() { setCurrentStep(activeStep.value + 1); }
async function saveCurrentProgress() { if (saving.value) return; saving.value = true; try { await persistProgress(); } finally { saving.value = false; } }
async function submitTask() { if (saving.value) return; saving.value = true; try { await persistProgress("SUBMIT"); } finally { saving.value = false; } }
async function resetTask() { if (saving.value) return; saving.value = true; try { form.value = createForm(); workRows.value = createRows(); activeStep.value = 1; await persistProgress("RESET"); proxy?.$modal?.msgSuccess("清空填写成功"); } finally { saving.value = false; } }
function exportOutcome() { const blob = new Blob([JSON.stringify(buildProgress(), null, 2)], { type: "application/json;charset=utf-8" }); const url = URL.createObjectURL(blob); const link = document.createElement("a"); link.href = url; link.download = `${taskTitle.value}-实训成果.json`; link.click(); URL.revokeObjectURL(url); }
</script>
<style scoped lang="scss">
.after-sales-page { display: grid; grid-template-columns: minmax(720px, 1fr) 340px; gap: 24px; min-height: calc(100vh - 76px); padding: 24px 24px 32px; color: #eef5ff; background: #06111d; }
.training-core { min-width: 0; padding: 28px; border: 1px solid rgba(0,180,255,.25); border-radius: 36px; background: rgba(8,18,28,.6); box-shadow: inset 0 1px 0 rgba(169,229,255,.08), 0 22px 48px rgba(0,0,0,.22); }
.task-header { margin-bottom: 24px; }.task-badge { display:inline-flex; align-items:center; gap:8px; min-height:28px; padding:4px 14px; border:1px solid rgba(99,217,255,.55); border-radius:999px; color:#dff5ff; background:rgba(17,126,178,.36); font-size:12px; font-weight:700; }.task-title { margin:12px 0 0; color:#fff; font-size:30px; font-weight:900; line-height:1.3; }
.task-card,.step-card { border:1px solid rgba(82,174,226,.42); border-radius:26px; background:rgba(0,25,42,.64); }.task-card { margin-top:28px; padding:18px 22px 22px; }.workbench-head { display:flex; align-items:flex-start; justify-content:space-between; gap:18px; margin-bottom:22px; padding-bottom:18px; border-bottom:1px solid rgba(0,180,255,.2); }.section-eyebrow { margin:0; color:#71dfff; font-size:12px; font-weight:800; line-height:1.4; }.workbench-head h3 { margin:4px 0 8px; color:#fff; font-size:26px; font-weight:800; line-height:1.3; }.workbench-description,.step-content p,.step-desc { margin:0; color:#d7ecff; font-size:15px; line-height:1.8; }.workbench-actions { display:flex; flex-wrap:wrap; justify-content:flex-end; margin-left:auto; gap:10px; flex-shrink:0; }
.outline-action,.btn-nav { display:inline-flex; align-items:center; justify-content:center; gap:8px; min-height:40px; padding:0 18px; border:1px solid rgba(99,217,255,.55); border-radius:999px; color:#e9fbff; background:rgba(17,126,178,.36); font:inherit; font-size:14px; font-weight:800; cursor:pointer; }.outline-action:hover,.outline-action:focus-visible,.btn-nav:hover:not(:disabled),.btn-nav:focus-visible { border-color:rgba(116,235,255,.85); background:rgba(18,146,204,.5); outline:none; transform:translateY(-1px); }
.step-indicator { display:flex; align-items:center; gap:12px; width:calc(100% + 24px); min-height:0; margin:0 -12px 32px; padding:18px 22px; overflow-x:auto; border:1px solid rgba(0,180,255,.3); border-radius:18px; background:linear-gradient(110deg,rgba(4,39,58,.9),rgba(2,20,33,.94)); box-shadow:inset 0 1px 0 rgba(169,229,255,.08); }.step-tab { display:flex; flex:1 0 145px; align-items:center; min-height:66px; padding:8px 10px; border:1px solid rgba(68,141,177,.35); border-radius:8px; color:#9ab3d0; background:rgba(3,27,43,.52); font:inherit; font-size:14px; font-weight:800; text-align:left; cursor:pointer; transition:transform .2s,color .2s,background .2s,border-color .2s,box-shadow .2s; }.step-tab:hover,.step-tab:focus-visible { transform:translateY(-2px); border-color:rgba(89,223,255,.82); color:#fff; background:rgba(8,92,131,.52); box-shadow:0 8px 18px rgba(0,0,0,.2); outline:none; }.step-tab.active { border-color:rgba(89,226,255,.85); color:#fff; background:linear-gradient(95deg,#0a6b9e,#0a5c86); box-shadow:0 8px 20px rgba(0,120,170,.22); }.step-marker { display:inline-flex; flex:0 0 38px; align-items:center; justify-content:center; width:38px; height:38px; border:1px solid rgba(113,223,255,.55); border-radius:50%; color:#bdefff; background:rgba(3,27,43,.72); font-size:13px; font-weight:900; }.step-copy { display:grid; min-width:0; gap:4px; margin-left:10px; }.step-copy strong { display:-webkit-box; overflow:hidden; color:inherit; font-size:14px; line-height:1.25; -webkit-box-orient:vertical; -webkit-line-clamp:2; }.step-copy span { color:#7ec7e7; font-size:12px; font-weight:700; }.step-tab.active .step-marker { border-color:#a8f3ff; color:#fff; background:linear-gradient(135deg,#0bb2ed,#0a6b9e); box-shadow:0 0 0 4px rgba(77,215,255,.13),0 0 18px rgba(77,215,255,.4); }.step-tab.complete .step-marker { border-color:#59e0ca; color:#dffbff; background:rgba(13,132,119,.5); }.step-connector { flex:0 0 28px; height:2px; background:rgba(77,167,220,.54); color:#78cfe9; font-size:16px; line-height:0; text-align:right; }.step-connector.complete { background:#55ddcc; color:#75f0df; }
.step-card { margin-top:32px; padding:18px 22px 22px; }.step-indicator + .step-card,.workbench-head + .step-card { margin-top:0; }.step-card + .step-card { margin-top:16px; }.step-title-row { margin-bottom:14px; }.step-title-row h3 { margin:4px 0 0; color:#fff; font-size:22px; font-weight:900; line-height:1.3; }.step-content h4 { margin:0 0 12px; color:#fff; font-size:22px; font-weight:900; line-height:1.3; }
.service-flow { display:grid; grid-template-columns:repeat(4,minmax(0,1fr)); gap:12px; margin:20px 0; }.service-flow article,.hint-card { border:1px solid rgba(0,180,255,.22); border-radius:18px; background:rgba(1,14,26,.72); }.service-flow article { display:grid; gap:6px; min-height:112px; padding:16px; }.service-flow strong { color:#e9fbff; font-size:15px; }.service-flow span { color:#b7d8e9; font-size:13px; line-height:1.65; }.hint-card { margin-top:20px; padding:14px 16px; color:#d7ecff; font-size:14px; line-height:1.75; }.hint-card strong { color:#71dfff; }
.field-block { display:block; margin:16px 0 0; }.field-block span { display:block; margin-bottom:8px; color:#dff5ff; font-size:14px; font-weight:800; line-height:1.6; }.field-block :deep(.el-input__wrapper),.field-block :deep(.el-textarea__inner),.table-wrap :deep(.el-textarea__inner) { border:1px solid rgba(45,95,126,.95); border-radius:14px; box-shadow:none; background:#0f1a24; }.field-block :deep(.el-input__wrapper) { min-height:42px; padding:0 14px; }.field-block :deep(.el-input__inner),.field-block :deep(.el-textarea__inner),.table-wrap :deep(.el-textarea__inner) { color:#eef5ff; font-size:14px; }.field-block :deep(.el-textarea__inner),.table-wrap :deep(.el-textarea__inner) { min-height:110px !important; padding:12px 14px; line-height:1.65; }.field-block :deep(.el-input__wrapper.is-focus),.field-block :deep(.el-textarea__inner:focus),.table-wrap :deep(.el-textarea__inner:focus) { border-color:rgba(92,224,255,.7); box-shadow:0 0 0 3px rgba(0,174,255,.13); }
.table-panel { margin-top:22px; }.panel-title { margin-bottom:12px; }.panel-title h4 { margin:0 0 4px; color:#fff; font-size:18px; font-weight:900; }.panel-title p { color:#9ab3d0; font-size:14px; }.table-wrap { overflow-x:auto; border:1px solid rgba(0,180,255,.22); border-radius:18px; background:rgba(1,14,26,.72); }.table-wrap table { width:100%; min-width:760px; border-collapse:collapse; }.table-wrap th,.table-wrap td { padding:12px; border-right:1px solid rgba(77,167,220,.2); border-bottom:1px solid rgba(77,167,220,.2); vertical-align:top; }.table-wrap thead th { color:#eefaff; background:rgba(8,55,82,.98); font-size:14px; font-weight:800; }.table-wrap tbody th { width:18%; color:#dff5ff; font-size:14px; }.table-wrap td { color:#d7ecff; font-size:14px; line-height:1.7; }.table-wrap tr:last-child th,.table-wrap tr:last-child td { border-bottom:0; }.table-wrap th:last-child,.table-wrap td:last-child { border-right:0; }
.step-navigation { display:flex; justify-content:center; gap:14px; margin-top:22px; }.btn-nav.btn-save,.btn-nav.btn-primary { border-color:rgba(92,224,255,.7); color:#fff; background:linear-gradient(95deg,#0b84bd,#096491); }.btn-nav:disabled { cursor:not-allowed; opacity:.45; transform:none; }.training-actions { display:flex; flex-wrap:wrap; justify-content:center; gap:52px; margin-top:36px; }.training-actions :deep(.training-action) { min-width:172px; height:64px; padding:0 28px; border:1px solid #2c83aa; border-radius:6px; color:#dff7ff; background:rgba(13,64,88,.62); font-size:24px; font-weight:900; }.training-actions :deep(.training-action:hover:not(.is-disabled)) { border-color:#46b5e7; color:#fff; background:rgba(18,85,116,.78); }
@media (max-width:1100px) { .after-sales-page { grid-template-columns:1fr; } }
@media (max-width:900px) { .after-sales-page { padding:14px; }.training-core { padding:18px; border-radius:24px; }.workbench-head,.workbench-actions,.step-navigation { flex-direction:column; align-items:stretch; }.workbench-actions,.outline-action,.btn-nav,.training-actions :deep(.training-action) { width:100%; }.step-indicator { align-items:stretch; flex-direction:column; width:100%; margin-right:0; margin-left:0; overflow:visible; border-radius:20px; }.step-tab { flex:0 0 auto; width:100%; }.step-connector { flex:0 0 22px; width:2px; height:22px; margin-left:29px; text-align:center; writing-mode:vertical-rl; }.service-flow { grid-template-columns:1fr; } }
.step-tab.active { border-color:rgba(89,226,255,.85); color:#fff; background:linear-gradient(115deg,rgba(4,109,155,.78),rgba(5,62,102,.64)); box-shadow:0 0 18px rgba(24,183,235,.22),inset 0 1px 0 rgba(176,246,255,.2); }.step-tab.active .step-marker { border-color:#72e8ff; color:#fff; background:linear-gradient(135deg,#08b7e8,#1375d0); box-shadow:0 0 0 5px rgba(25,179,237,.14),0 0 18px rgba(46,208,255,.58); }.step-tab.complete { color:#dffbff; }.step-tab.complete .step-marker { border-color:rgba(84,230,221,.85); color:#062b37; background:#6ef0e1; box-shadow:0 0 12px rgba(79,231,218,.35); }.step-connector.complete { background:linear-gradient(90deg,#6ef0e1,#1cb8e9); color:#63e6f1; box-shadow:0 0 9px rgba(53,218,235,.46); }
/* Standard page step navigation */
.step-indicator { position:relative; display:flex; align-items:center; gap:0; width:calc(100% + 24px); margin:0 -12px 32px; padding:18px 22px; overflow-x:auto; border:1px solid rgba(0,180,255,.3); border-radius:18px; background:linear-gradient(90deg,rgba(6,42,61,.58),rgba(1,18,31,.42)),rgba(0,0,0,.3); box-shadow:inset 0 1px 0 rgba(145,233,255,.08); scrollbar-width:thin; }
.step-tab { display:flex; flex:1 0 145px; align-items:center; min-width:0; min-height:66px; padding:8px 10px; border:1px solid rgba(68,141,177,.35); border-radius:8px; color:#9ab3d0; background:rgba(3,27,43,.52); box-shadow:inset 0 1px 0 rgba(135,221,255,.04); font:inherit; font-size:14px; font-weight:800; text-align:left; cursor:pointer; transition:transform .2s ease,color .2s ease,border-color .2s ease,background .2s ease,box-shadow .2s ease; }
.step-tab:hover { transform:translateY(-2px); border-color:rgba(89,223,255,.82); color:#fff; background:rgba(8,92,131,.52); box-shadow:0 7px 18px rgba(0,0,0,.24),inset 0 1px 0 rgba(152,239,255,.16); }
.step-tab:hover .step-action { color:#9bf4ff; }
.step-tab:focus-visible { outline:2px solid rgba(92,224,255,.7); outline-offset:2px; }
.step-tab.active { border-color:rgba(89,226,255,0.85); color:#fff; background:linear-gradient(115deg,rgba(4,109,155,0.78),rgba(5,62,102,0.64)); box-shadow:0 0 18px rgba(24,183,235,.22),inset 0 1px 0 rgba(176,246,255,.2); }
.step-marker { display:inline-flex; flex:0 0 38px; align-items:center; justify-content:center; width:38px; height:38px; border:1px solid rgba(101,176,208,.6); border-radius:50%; color:#a6c4d9; background:rgba(3,25,40,.8); box-shadow:inset 0 0 12px rgba(38,174,233,.08); font-size:12px; font-weight:900; letter-spacing:.04em; }
.step-copy { display:grid; min-width:0; gap:4px; margin-left:10px; }
.step-name { display:-webkit-box; overflow:hidden; color:inherit; font-size:14px; font-weight:800; line-height:1.25; text-overflow:ellipsis; -webkit-box-orient:vertical; -webkit-line-clamp:2; }
.step-action { color:#66b6d4; font-size:10px; font-weight:800; letter-spacing:.06em; line-height:1; }
.step-tab.active .step-marker { border-color:#72e8ff; color:#fff; background:linear-gradient(135deg,#08b7e8,#1375d0); box-shadow:0 0 0 5px rgba(25,179,237,.14),0 0 18px rgba(46,208,255,.58); }
.step-tab.complete .step-marker { border-color:rgba(84,230,221,.85); color:#062b37; background:#6ef0e1; box-shadow:0 0 12px rgba(79,231,218,.35); }
.step-connector { position:relative; flex:0 1 40px; min-width:18px; height:2px; margin:0 8px; overflow:visible; background:rgba(98,169,201,.34); }
.step-connector::after { position:absolute; top:50%; right:-1px; width:6px; height:6px; border-top:1px solid #73b1ce; border-right:1px solid #73b1ce; content:""; transform:translateY(-50%) rotate(45deg); }
.step-tab.complete + .step-connector { background:linear-gradient(90deg,#6ef0e1,#1cb8e9); box-shadow:0 0 9px rgba(53,218,235,.46); }
.step-tab.complete + .step-connector::after { border-color:#63e6f1; }
@media (max-width:900px) { .step-indicator { align-items:stretch; flex-direction:column; width:100%; margin-right:0; margin-left:0; overflow:visible; border-radius:20px; } .step-tab { flex:0 0 auto; width:100%; } .step-connector { flex:0 0 20px; min-width:0; width:2px; height:20px; margin-left:29px; } }
.workbench-head--actions-only {
justify-content: flex-end;
margin-bottom: 18px;
padding-bottom: 0;
border-bottom: 0;
}
</style>