/* ============================================================================= components-tier3-supplement.css Tier 3 supplement — 12 components added after Tier 3 main set. Pinned rules: - No big pink fills for text. Use surface bg + colored border + dark body text. - severity-critical (#A40E26) ≠ state-failed (#7D1A1A). Don't conflate. - Light + dark theme via existing tokens only. ============================================================================= */ /* ========================================================================= 1. Sankey / Toxic-Flow Chain (.tfa-flow) 3-step: Input → Access → Exfil with mitigation shields breaking the chain. ========================================================================= */ .tfa-flow { display: grid; grid-template-columns: 1fr auto 1fr auto 1fr; gap: 0; align-items: stretch; background: var(--color-surface); border: 1px solid var(--color-border-subtle); border-radius: var(--radius-lg); padding: var(--space-5); position: relative; } .tfa-flow__verdict { position: absolute; top: -12px; right: var(--space-5); padding: 4px 10px; font-size: 11px; font-weight: var(--font-weight-bold); letter-spacing: 0.06em; border-radius: var(--radius-pill); background: var(--color-severity-critical); color: #fff; } .tfa-flow__verdict[data-verdict="ALLOW"] { background: var(--color-state-success); } .tfa-flow__verdict[data-verdict="WARN"] { background: var(--color-severity-medium); color: #fff; } .tfa-flow__verdict[data-verdict="BLOCK"] { background: var(--color-severity-critical); } .tfa-leg { display: flex; flex-direction: column; gap: 6px; padding: var(--space-3); background: var(--color-surface); border: 1px solid var(--color-border-subtle); border-left-width: 4px; border-radius: var(--radius-md); cursor: pointer; transition: background var(--duration-fast) var(--ease-default); text-align: left; } .tfa-leg:hover { background: var(--color-bg-soft); } .tfa-leg:focus-visible { outline: none; box-shadow: var(--shadow-focus); } .tfa-leg[data-severity="medium"] { border-left-color: var(--color-severity-medium); } .tfa-leg[data-severity="high"] { border-left-color: var(--color-severity-high); } .tfa-leg[data-severity="critical"] { border-left-color: var(--color-severity-critical); } .tfa-leg__label { font-size: 11px; text-transform: uppercase; letter-spacing: 0.08em; color: var(--color-text-tertiary); font-weight: var(--font-weight-semibold); } .tfa-leg__name { font-size: var(--font-size-md); font-weight: var(--font-weight-semibold); color: var(--color-text-primary); } .tfa-leg__source { font-family: var(--font-family-mono); font-size: 12px; color: var(--color-text-secondary); } .tfa-leg__status { margin-top: auto; font-size: 11px; font-weight: var(--font-weight-medium); display: inline-flex; align-items: center; gap: 4px; } .tfa-leg__status[data-mit="unmitigated"] { color: var(--color-severity-critical); } .tfa-leg__status[data-mit="partially_mitigated"] { color: var(--color-severity-medium); } .tfa-leg__status[data-mit="mitigated"] { color: var(--color-state-success); } /* Arrow connectors. Width grows with severity */ .tfa-arrow { display: flex; align-items: center; justify-content: center; position: relative; min-width: 56px; padding: 0 4px; } .tfa-arrow__line { height: 4px; width: 100%; background: var(--color-border-moderate); position: relative; } .tfa-arrow[data-severity="medium"] .tfa-arrow__line { background: var(--color-severity-medium); height: 6px; } .tfa-arrow[data-severity="high"] .tfa-arrow__line { background: var(--color-severity-high); height: 8px; } .tfa-arrow[data-severity="critical"] .tfa-arrow__line { background: var(--color-severity-critical); height: 10px; } .tfa-arrow__line::after { content: ""; position: absolute; right: -1px; top: 50%; width: 0; height: 0; border-left: 10px solid currentColor; border-top: 8px solid transparent; border-bottom: 8px solid transparent; transform: translateY(-50%); color: inherit; } .tfa-arrow[data-severity="medium"] .tfa-arrow__line { color: var(--color-severity-medium); } .tfa-arrow[data-severity="high"] .tfa-arrow__line { color: var(--color-severity-high); } .tfa-arrow[data-severity="critical"] .tfa-arrow__line { color: var(--color-severity-critical); } .tfa-arrow__shield { position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); width: 32px; height: 32px; background: var(--color-state-success); color: #fff; border-radius: 50%; display: flex; align-items: center; justify-content: center; border: 3px solid var(--color-surface); font-size: 16px; } .tfa-arrow--mitigated .tfa-arrow__line { background: repeating-linear-gradient(90deg, var(--color-state-success) 0 4px, transparent 4px 8px); } @media (max-width: 720px) { .tfa-flow { grid-template-columns: 1fr; grid-template-rows: auto auto auto auto auto; } .tfa-arrow { min-height: 48px; min-width: auto; } .tfa-arrow__line { width: 4px; height: 100%; } .tfa-arrow[data-severity="medium"] .tfa-arrow__line { width: 6px; height: 100%; } .tfa-arrow[data-severity="high"] .tfa-arrow__line { width: 8px; height: 100%; } .tfa-arrow[data-severity="critical"] .tfa-arrow__line { width: 10px; height: 100%; } .tfa-arrow__line::after { right: 50%; top: auto; bottom: -1px; transform: translateX(50%); border-left: 8px solid transparent; border-right: 8px solid transparent; border-top: 10px solid currentColor; border-bottom: none; } } /* ========================================================================= 2. Fleet-Overview (.fleet-grid, .fleet-tile) ========================================================================= */ .fleet-toolbar { display: flex; gap: var(--space-3); flex-wrap: wrap; align-items: center; padding: var(--space-3) var(--space-4); background: var(--color-bg-soft); border: 1px solid var(--color-border-subtle); border-radius: var(--radius-md); margin-bottom: var(--space-3); } .fleet-toolbar__label { font-size: 11px; text-transform: uppercase; letter-spacing: 0.06em; color: var(--color-text-tertiary); font-weight: var(--font-weight-semibold); } .fleet-toolbar__spacer { flex: 1; } .fleet-toolbar__count { font-size: var(--font-size-sm); color: var(--color-text-secondary); } .fleet-grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: var(--space-3); } @media (max-width: 980px) { .fleet-grid { grid-template-columns: repeat(2, 1fr); } } @media (max-width: 540px) { .fleet-grid { grid-template-columns: 1fr; } } .fleet-tile { background: var(--color-surface); border: 1px solid var(--color-border-subtle); border-radius: var(--radius-md); padding: var(--space-3); display: grid; grid-template-rows: auto auto auto auto; gap: 6px; cursor: pointer; transition: border-color var(--duration-fast), transform var(--duration-fast); } .fleet-tile:hover { border-color: var(--color-primary-300); transform: translateY(-1px); } .fleet-tile:focus-visible { outline: none; box-shadow: var(--shadow-focus); } .fleet-tile__row { display: flex; justify-content: space-between; align-items: center; gap: 8px; } .fleet-tile__name { font-family: var(--font-family-mono); font-size: 12px; color: var(--color-text-primary); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; flex: 1; } .fleet-tile__grade { width: 28px; height: 28px; display: flex; align-items: center; justify-content: center; font-weight: var(--font-weight-bold); font-size: 13px; border-radius: var(--radius-sm); color: #fff; flex-shrink: 0; } .fleet-tile__grade[data-grade="A"] { background: var(--color-state-success); } .fleet-tile__grade[data-grade="B"] { background: #4D8E2F; } .fleet-tile__grade[data-grade="C"] { background: var(--color-severity-medium); } .fleet-tile__grade[data-grade="D"] { background: var(--color-severity-high); } .fleet-tile__grade[data-grade="E"] { background: var(--color-severity-critical); } .fleet-tile__grade[data-grade="F"] { background: var(--color-severity-extreme); } .fleet-tile__meter { height: 6px; border-radius: 3px; background: var(--color-bg-soft); overflow: hidden; position: relative; } .fleet-tile__meter-fill { height: 100%; border-radius: 3px; } .fleet-tile__meter-fill[data-band="1"] { background: var(--color-state-success); } .fleet-tile__meter-fill[data-band="2"] { background: var(--color-severity-medium); } .fleet-tile__meter-fill[data-band="3"] { background: var(--color-severity-high); } .fleet-tile__meter-fill[data-band="4"] { background: var(--color-severity-critical); } .fleet-tile__chip { display: inline-flex; align-items: center; font-size: 11px; padding: 2px 8px; border-radius: var(--radius-pill); background: var(--color-bg-soft); color: var(--color-text-secondary); border: 1px solid var(--color-border-subtle); width: fit-content; } .fleet-tile__meta { display: flex; justify-content: space-between; font-size: 11px; color: var(--color-text-tertiary); font-family: var(--font-family-mono); } .fleet-tile__trend--better { color: var(--color-state-success); } .fleet-tile__trend--worse { color: var(--color-severity-critical); } .fleet-tile__trend--stable { color: var(--color-text-tertiary); } /* ========================================================================= 3. Kanban Keep / Review / Remove (.kanban-board) ========================================================================= */ .kanban-board { display: grid; grid-template-columns: repeat(3, 1fr); gap: var(--space-4); } @media (max-width: 820px) { .kanban-board { grid-template-columns: 1fr; } } .kanban-col { background: var(--color-bg-soft); border: 1px solid var(--color-border-subtle); border-radius: var(--radius-md); padding: var(--space-3); display: flex; flex-direction: column; gap: var(--space-3); min-height: 320px; } .kanban-col__head { display: flex; align-items: center; justify-content: space-between; padding-bottom: var(--space-2); border-bottom: 2px solid var(--color-border-subtle); } .kanban-col[data-bucket="keep"] .kanban-col__head { border-bottom-color: var(--color-state-success); } .kanban-col[data-bucket="review"] .kanban-col__head { border-bottom-color: var(--color-state-warning); } .kanban-col[data-bucket="remove"] .kanban-col__head { border-bottom-color: var(--color-severity-critical); } .kanban-col__title { font-size: var(--font-size-md); font-weight: var(--font-weight-semibold); color: var(--color-text-primary); } .kanban-col__count { font-family: var(--font-family-mono); font-size: 12px; background: var(--color-surface); padding: 2px 8px; border-radius: var(--radius-pill); color: var(--color-text-secondary); border: 1px solid var(--color-border-subtle); } .kanban-card { background: var(--color-surface); border: 1px solid var(--color-border-subtle); border-radius: var(--radius-md); padding: var(--space-3); cursor: grab; display: flex; flex-direction: column; gap: 6px; transition: box-shadow var(--duration-fast); } .kanban-card:hover { box-shadow: var(--shadow-md); } .kanban-card[data-verdict="BLOCK"] { border-color: var(--color-severity-critical); border-left-width: 4px; } .kanban-card[data-verdict="trusted"] { border-left: 4px solid var(--color-state-success); } .kanban-card[data-verdict="unknown"] { border-left: 4px solid var(--color-state-warning); } .kanban-card__name { font-family: var(--font-family-mono); font-size: 13px; color: var(--color-text-primary); word-break: break-word; overflow-wrap: anywhere; } .kanban-card__meta { font-size: 11px; color: var(--color-text-tertiary); } .kanban-card__reason { font-size: 12px; color: var(--color-text-secondary); } .kanban-col__empty { margin: auto; text-align: center; color: var(--color-text-tertiary); font-size: var(--font-size-sm); padding: var(--space-4); } .kanban-col__empty button { margin-top: var(--space-2); } .kanban-actions { display: flex; gap: 4px; margin-top: 4px; } .kanban-actions button { flex: 1; font-size: 11px; padding: 4px 6px; background: var(--color-bg-soft); border: 1px solid var(--color-border-subtle); border-radius: var(--radius-sm); color: var(--color-text-secondary); cursor: pointer; font-family: inherit; } .kanban-actions button:hover { background: var(--color-surface-sunken); color: var(--color-text-primary); } /* ========================================================================= 4. Maturity-Ladder (.mat-ladder) ========================================================================= */ .mat-ladder { display: flex; flex-direction: column; background: var(--color-surface); border: 1px solid var(--color-border-subtle); border-radius: var(--radius-md); padding: var(--space-4); gap: 0; } .mat-step { display: grid; grid-template-columns: 56px 1fr; gap: var(--space-4); padding: var(--space-3) 0; position: relative; } .mat-step + .mat-step { border-top: 1px dashed var(--color-border-subtle); } .mat-step__icon { width: 44px; height: 44px; border-radius: 50%; display: flex; align-items: center; justify-content: center; background: var(--color-surface); border: 2px solid var(--color-border-moderate); color: var(--color-text-tertiary); font-weight: var(--font-weight-semibold); font-size: 15px; position: relative; z-index: 1; } .mat-step[data-state="completed"] .mat-step__icon { background: var(--color-state-success); border-color: var(--color-state-success); color: #fff; } .mat-step[data-state="current"] .mat-step__icon { border-color: var(--color-primary-500); color: var(--color-primary-700); background: var(--color-surface); } /* progress ring around current step */ .mat-step__ring { position: absolute; inset: -4px; border-radius: 50%; pointer-events: none; } .mat-step__ring svg { width: 100%; height: 100%; transform: rotate(-90deg); } .mat-step__ring circle { fill: none; stroke-width: 3; } .mat-step__ring .ring-bg { stroke: var(--color-border-subtle); } .mat-step__ring .ring-fill { stroke: var(--color-primary-500); } .mat-step__name { font-size: var(--font-size-md); font-weight: var(--font-weight-semibold); color: var(--color-text-primary); display: flex; align-items: center; gap: 8px; } .mat-step[data-state="completed"] .mat-step__name { color: var(--color-text-secondary); } .mat-step[data-state="future"] .mat-step__name { color: var(--color-text-tertiary); } .mat-step__pill { font-size: 11px; padding: 2px 8px; border-radius: var(--radius-pill); text-transform: uppercase; letter-spacing: 0.06em; font-weight: var(--font-weight-semibold); } .mat-step__pill--current { background: var(--color-primary-100); color: var(--color-primary-700); } .mat-step__pill--complete { background: transparent; color: var(--color-state-success); border: 1px solid currentColor; } .mat-step__desc { font-size: var(--font-size-sm); color: var(--color-text-secondary); margin-top: 2px; max-width: 60ch; } .mat-step__progress { margin-top: 6px; display: flex; align-items: center; gap: 8px; font-size: 12px; color: var(--color-text-tertiary); } .mat-step__progress-bar { flex: 1; height: 4px; background: var(--color-bg-soft); border-radius: 2px; overflow: hidden; max-width: 200px; } .mat-step__progress-fill { height: 100%; background: var(--color-primary-500); border-radius: 2px; } /* ========================================================================= 5. Classify-and-Transform / 5-Bucket-Sorter (.cls-sorter) ========================================================================= */ .cls-sorter { display: flex; flex-direction: column; gap: var(--space-4); } .cls-input { background: var(--color-surface); border: 1px solid var(--color-border-subtle); border-radius: var(--radius-md); padding: var(--space-3); } .cls-input textarea { width: 100%; min-height: 100px; font-family: var(--font-family-sans); font-size: var(--font-size-sm); border: 1px solid var(--color-border-subtle); border-radius: var(--radius-sm); padding: var(--space-2) var(--space-3); background: var(--color-bg); color: var(--color-text-primary); resize: vertical; } .cls-input textarea:focus { outline: none; box-shadow: var(--shadow-focus); border-color: var(--color-border-focus); } .cls-buckets { display: grid; grid-template-columns: repeat(5, 1fr); gap: var(--space-3); } @media (max-width: 1100px) { .cls-buckets { grid-template-columns: repeat(3, 1fr); } } @media (max-width: 720px) { .cls-buckets { grid-template-columns: repeat(2, 1fr); } } @media (max-width: 460px) { .cls-buckets { grid-template-columns: 1fr; } } .cls-bucket { background: var(--color-surface); border: 1px solid var(--color-border-subtle); border-top-width: 4px; border-radius: var(--radius-md); padding: var(--space-3); display: flex; flex-direction: column; gap: var(--space-2); min-height: 200px; } .cls-bucket[data-egnethet="lav"] { border-top-color: var(--color-text-tertiary); } .cls-bucket[data-egnethet="medium"] { border-top-color: var(--color-state-info); } .cls-bucket[data-egnethet="hoy"] { border-top-color: var(--color-state-success); } .cls-bucket__head { display: flex; flex-direction: column; gap: 2px; padding-bottom: var(--space-2); border-bottom: 1px solid var(--color-border-subtle); } .cls-bucket__title { font-size: var(--font-size-sm); font-weight: var(--font-weight-semibold); color: var(--color-text-primary); } .cls-bucket__egnethet { font-size: 10px; text-transform: uppercase; letter-spacing: 0.08em; color: var(--color-text-tertiary); font-weight: var(--font-weight-semibold); } .cls-bucket[data-egnethet="lav"] .cls-bucket__egnethet { color: var(--color-text-tertiary); } .cls-bucket[data-egnethet="medium"] .cls-bucket__egnethet { color: var(--color-state-info); } .cls-bucket[data-egnethet="hoy"] .cls-bucket__egnethet { color: var(--color-state-success); } .cls-item { background: var(--color-bg-soft); border: 1px solid var(--color-border-subtle); border-radius: var(--radius-sm); padding: 6px 8px; font-size: 12px; color: var(--color-text-primary); cursor: grab; display: flex; flex-direction: column; gap: 2px; } .cls-item__action { font-size: 10px; text-transform: uppercase; letter-spacing: 0.06em; color: var(--color-text-tertiary); font-weight: var(--font-weight-medium); } .cls-bucket__action { margin-top: auto; padding-top: var(--space-2); border-top: 1px dashed var(--color-border-subtle); } .cls-bucket__empty { font-size: 12px; color: var(--color-text-tertiary); font-style: italic; text-align: center; padding: var(--space-3); } /* ========================================================================= 6. Cycle Position Ribbon (.cycle-ribbon) ========================================================================= */ .cycle-ribbon { position: relative; background: var(--color-surface); border-bottom: 1px solid var(--color-border-subtle); padding: 8px var(--space-5); display: flex; align-items: center; gap: var(--space-4); font-size: 13px; cursor: pointer; overflow: hidden; } .cycle-ribbon::before { content: ""; position: absolute; inset: 0; background: var(--color-state-info); opacity: 0.06; width: var(--cycle-progress, 0%); transition: width var(--duration-normal); } .cycle-ribbon[data-phase="planning"] { border-bottom-color: var(--color-state-info); } .cycle-ribbon[data-phase="planning"]::before { background: var(--color-state-info); } .cycle-ribbon[data-phase="execution"] { border-bottom-color: var(--color-state-success); } .cycle-ribbon[data-phase="execution"]::before { background: var(--color-state-success); } .cycle-ribbon[data-phase="retrospective_prep"] { border-bottom-color: var(--color-severity-medium); } .cycle-ribbon[data-phase="retrospective_prep"]::before { background: var(--color-severity-medium); } .cycle-ribbon > * { position: relative; z-index: 1; } .cycle-ribbon__id { font-family: var(--font-family-mono); font-weight: var(--font-weight-semibold); color: var(--color-text-primary); white-space: nowrap; flex-shrink: 0; } .cycle-ribbon__week { color: var(--color-text-secondary); font-family: var(--font-family-mono); white-space: nowrap; flex-shrink: 0; } .cycle-ribbon__phase { font-size: 11px; padding: 2px 8px; border-radius: var(--radius-pill); text-transform: uppercase; letter-spacing: 0.06em; font-weight: var(--font-weight-semibold); white-space: nowrap; flex-shrink: 0; } .cycle-ribbon[data-phase="planning"] .cycle-ribbon__phase { background: var(--color-primary-100); color: var(--color-primary-700); } .cycle-ribbon[data-phase="execution"] .cycle-ribbon__phase { background: var(--color-severity-low-soft); color: var(--color-severity-low-on); } .cycle-ribbon[data-phase="retrospective_prep"] .cycle-ribbon__phase { background: var(--color-severity-medium-soft); color: var(--color-severity-medium-on); } .cycle-ribbon__msg { color: var(--color-text-secondary); flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } .cycle-ribbon__chev { color: var(--color-text-tertiary); transition: transform var(--duration-fast); } .cycle-ribbon[aria-expanded="true"] .cycle-ribbon__chev { transform: rotate(180deg); } .cycle-ribbon__panel { background: var(--color-bg-soft); border-bottom: 1px solid var(--color-border-subtle); padding: var(--space-4) var(--space-5); display: none; font-size: var(--font-size-sm); } .cycle-ribbon__panel[data-open="true"] { display: block; } @media (max-width: 720px) { .cycle-ribbon__msg { display: none; } } /* ========================================================================= 7. Persistent-Antipattern Badge (.pap-badge) ========================================================================= */ .pap-badge { display: inline-flex; align-items: center; gap: 6px; padding: 4px 10px; background: var(--color-surface); border: 1px solid var(--color-severity-critical); border-radius: var(--radius-pill); font-size: 12px; font-weight: var(--font-weight-medium); color: var(--color-severity-critical); cursor: pointer; position: relative; } .pap-badge::before { content: ""; width: 8px; height: 8px; border-radius: 50%; background: var(--color-severity-critical); animation: pap-pulse 2.4s var(--ease-default) infinite; } @keyframes pap-pulse { 0%, 100% { opacity: 1; transform: scale(1); } 50% { opacity: 0.45; transform: scale(0.7); } } @media (prefers-reduced-motion: reduce) { .pap-badge::before { animation: none; opacity: 1; } } .pap-badge__count { font-family: var(--font-family-mono); font-weight: var(--font-weight-semibold); } .pap-detail { margin-top: var(--space-3); background: var(--color-surface); border: 1px solid var(--color-severity-critical); border-left-width: 4px; border-radius: var(--radius-md); padding: var(--space-4); display: none; } .pap-detail[data-open="true"] { display: block; } .pap-detail h4 { margin: 0 0 4px; color: var(--color-severity-critical); font-size: var(--font-size-md); } .pap-detail__cycles { display: flex; gap: 4px; flex-wrap: wrap; margin: var(--space-2) 0; } .pap-detail__cycle { font-family: var(--font-family-mono); font-size: 11px; padding: 2px 6px; background: var(--color-bg-soft); border-radius: var(--radius-sm); color: var(--color-text-secondary); } .pap-detail__rec { background: var(--color-bg-soft); border-radius: var(--radius-sm); padding: var(--space-2) var(--space-3); margin-top: var(--space-2); font-size: var(--font-size-sm); color: var(--color-text-primary); } /* one-shot variant */ .pap-badge--oneshot { border-style: dashed; border-color: var(--color-severity-medium); color: var(--color-severity-medium); } .pap-badge--oneshot::before { display: none; } /* ========================================================================= 8. Suppressed-Signals Panel (.suppressed) ========================================================================= */ .suppressed { background: var(--color-bg-soft); border: 1px solid var(--color-border-subtle); border-radius: var(--radius-md); overflow: hidden; } .suppressed__head { width: 100%; display: flex; align-items: center; gap: var(--space-3); padding: var(--space-3) var(--space-4); background: transparent; border: 0; cursor: pointer; font-family: inherit; text-align: left; color: var(--color-text-secondary); } .suppressed__head:hover { background: var(--color-surface-sunken); color: var(--color-text-primary); } .suppressed__head:focus-visible { outline: none; box-shadow: var(--shadow-focus); } .suppressed__chev { color: var(--color-text-tertiary); transition: transform var(--duration-fast); } .suppressed[aria-expanded="true"] .suppressed__chev { transform: rotate(90deg); } .suppressed__label { font-size: var(--font-size-sm); } .suppressed__count { font-family: var(--font-family-mono); font-size: 12px; background: var(--color-surface); padding: 2px 8px; border-radius: var(--radius-pill); color: var(--color-text-secondary); border: 1px solid var(--color-border-subtle); margin-left: auto; } .suppressed__body { display: none; padding: 0 var(--space-4) var(--space-4); } .suppressed[aria-expanded="true"] .suppressed__body { display: block; } .suppressed-group { background: var(--color-surface); border: 1px solid var(--color-border-subtle); border-radius: var(--radius-sm); padding: var(--space-3); } .suppressed-group + .suppressed-group { margin-top: var(--space-2); } .suppressed-group__head { display: flex; justify-content: space-between; align-items: center; gap: 8px; margin-bottom: 4px; } .suppressed-group__reason { font-family: var(--font-family-mono); font-size: 12px; color: var(--color-text-tertiary); } .suppressed-group__count { font-size: 11px; color: var(--color-text-tertiary); } .suppressed-group__desc { font-size: var(--font-size-sm); color: var(--color-text-secondary); margin: 0 0 6px; } .suppressed-group__examples { display: flex; gap: 4px; flex-wrap: wrap; } .suppressed-group__example { font-family: var(--font-family-mono); font-size: 11px; background: var(--color-bg-soft); padding: 2px 6px; border-radius: var(--radius-sm); color: var(--color-text-secondary); } /* ========================================================================= 9. ExpansionCard (Aksel) (.expansion) ========================================================================= */ .expansion { background: var(--color-surface); border: 1px solid var(--color-border-subtle); border-radius: var(--radius-md); overflow: hidden; } .expansion + .expansion { margin-top: var(--space-2); } .expansion__head { width: 100%; display: flex; align-items: flex-start; gap: var(--space-3); padding: var(--space-3) var(--space-4); background: transparent; border: 0; cursor: pointer; font-family: inherit; text-align: left; } .expansion__head:hover { background: var(--color-bg-soft); } .expansion__head:focus-visible { outline: none; box-shadow: var(--shadow-focus); } .expansion__title { flex: 1; } .expansion__title-main { display: block; font-size: var(--font-size-md); color: var(--color-text-primary); font-weight: var(--font-weight-medium); } .expansion__title-sub { display: block; font-size: var(--font-size-sm); color: var(--color-text-secondary); margin-top: 2px; } .expansion__chev { color: var(--color-text-tertiary); transition: transform var(--duration-normal) var(--ease-default); flex-shrink: 0; margin-top: 2px; } .expansion[aria-expanded="true"] .expansion__chev { transform: rotate(180deg); } .expansion__body { display: grid; grid-template-rows: 0fr; transition: grid-template-rows var(--duration-normal) var(--ease-default); } .expansion[aria-expanded="true"] .expansion__body { grid-template-rows: 1fr; } .expansion__body-inner { overflow: hidden; } .expansion__body-inner > div { padding: 0 var(--space-4) var(--space-4); border-top: 1px solid var(--color-border-subtle); padding-top: var(--space-3); margin-top: -1px; } @media (prefers-reduced-motion: reduce) { .expansion__body { transition: none; } } /* ========================================================================= 10. ReadMore (Aksel) (.read-more) ========================================================================= */ .read-more { display: inline; } .read-more__trigger { display: inline-flex; align-items: center; gap: 4px; background: transparent; border: 0; color: var(--color-text-link); font-family: inherit; font-size: inherit; font-weight: var(--font-weight-medium); cursor: pointer; padding: 0; text-decoration: underline; text-decoration-thickness: 1px; text-underline-offset: 3px; } .read-more__trigger:hover { color: var(--color-text-link-hover); } .read-more__trigger:focus-visible { outline: none; box-shadow: var(--shadow-focus); border-radius: 2px; } .read-more__chev { transition: transform var(--duration-fast); } .read-more[aria-expanded="true"] .read-more__chev { transform: rotate(180deg); } .read-more__body { display: none; margin-top: var(--space-2); } .read-more[aria-expanded="true"] .read-more__body { display: block; } /* ========================================================================= 11. FormProgress (Aksel multi-step skjema) (.form-progress) ========================================================================= */ .form-progress { background: var(--color-surface); border: 1px solid var(--color-border-subtle); border-radius: var(--radius-md); padding: var(--space-4); display: flex; flex-direction: column; gap: var(--space-3); width: 280px; position: sticky; top: var(--space-4); } .form-progress__autosave { display: flex; align-items: center; gap: 6px; font-size: 12px; color: var(--color-text-tertiary); padding-bottom: var(--space-2); border-bottom: 1px solid var(--color-border-subtle); } .form-progress__autosave-dot { width: 6px; height: 6px; border-radius: 50%; background: var(--color-state-success); } .form-progress__steps { display: flex; flex-direction: column; gap: 2px; } .fp-step { display: grid; grid-template-columns: 28px 1fr; gap: var(--space-2); align-items: start; padding: 8px; border-radius: var(--radius-sm); text-align: left; background: transparent; border: 0; cursor: pointer; font-family: inherit; position: relative; } .fp-step:hover { background: var(--color-bg-soft); } .fp-step:focus-visible { outline: none; box-shadow: var(--shadow-focus); } .fp-step[disabled] { cursor: not-allowed; opacity: 0.5; } .fp-step__num { width: 22px; height: 22px; border-radius: 50%; display: flex; align-items: center; justify-content: center; background: var(--color-surface); border: 1.5px solid var(--color-border-moderate); color: var(--color-text-tertiary); font-size: 11px; font-weight: var(--font-weight-semibold); } .fp-step[data-state="done"] .fp-step__num { background: var(--color-state-success); border-color: var(--color-state-success); color: #fff; } .fp-step[data-state="in-progress"] .fp-step__num { border-color: var(--color-primary-500); color: var(--color-primary-700); font-weight: var(--font-weight-bold); } .fp-step__name { font-size: var(--font-size-sm); color: var(--color-text-primary); font-weight: var(--font-weight-medium); } .fp-step[data-state="done"] .fp-step__name { color: var(--color-text-secondary); font-weight: var(--font-weight-regular); } .fp-step[data-state="in-progress"] .fp-step__name { color: var(--color-primary-700); font-weight: var(--font-weight-semibold); } .fp-step__progress { margin-top: 4px; font-size: 11px; color: var(--color-text-tertiary); display: flex; align-items: center; gap: 6px; } .fp-step__bar { flex: 1; height: 3px; background: var(--color-bg-soft); border-radius: 2px; overflow: hidden; max-width: 80px; } .fp-step__bar-fill { height: 100%; background: var(--color-primary-500); } .form-progress__remaining { padding-top: var(--space-2); border-top: 1px solid var(--color-border-subtle); font-size: 12px; color: var(--color-text-tertiary); display: flex; justify-content: space-between; } /* ========================================================================= 12. Aspirational vs Committed Visual (.okr-mode) Modifier added to OKR Objective cards ========================================================================= */ .okr-mode { position: relative; background: var(--color-surface); border: 1px solid var(--color-border-subtle); border-radius: var(--radius-md); padding: var(--space-4); } .okr-mode__gauge { position: relative; width: 88px; height: 88px; display: flex; align-items: center; justify-content: center; flex-shrink: 0; } .okr-mode__gauge svg { position: absolute; inset: 0; transform: rotate(-90deg); width: 100%; height: 100%; } .okr-mode__gauge circle.gauge-bg { fill: none; stroke: var(--color-border-subtle); stroke-width: 6; } .okr-mode__gauge circle.gauge-fill { fill: none; stroke: var(--color-state-success); stroke-width: 6; stroke-linecap: round; } .okr-mode__gauge .gauge-value { font-family: var(--font-family-mono); font-size: 22px; font-weight: var(--font-weight-bold); color: var(--color-text-primary); position: relative; z-index: 1; } /* aspirational variant — dashed stroke */ .okr-mode[data-mode="aspirational"] .okr-mode__gauge circle.gauge-fill { stroke: var(--color-scope-okr); stroke-dasharray: 6 4; } .okr-mode__badge { position: absolute; top: var(--space-2); right: var(--space-2); font-size: 10px; font-weight: var(--font-weight-bold); letter-spacing: 0.08em; padding: 2px 8px; border-radius: var(--radius-sm); } .okr-mode[data-mode="aspirational"] .okr-mode__badge { background: transparent; color: var(--color-scope-okr); border: 1px dashed var(--color-scope-okr); } .okr-mode[data-mode="committed"] .okr-mode__badge { background: var(--color-primary-700); color: #fff; } .okr-mode__row { display: flex; gap: var(--space-4); align-items: center; } .okr-mode__objective { font-size: var(--font-size-md); color: var(--color-text-primary); flex: 1; } .okr-mode__hint { font-size: 12px; color: var(--color-text-tertiary); margin-top: 4px; } /* ============================================================================= v0.3 ADDITIONS — playground/report-page foundation primitives. Originally defined inline in plugin playgrounds (ms-ai-architect v1.10). Hoisted here so all 5 plugin consumers share the same vocabulary. ============================================================================= */ /* ========================================================================= 13. Eyebrow utility (.eyebrow) Uppercase mini-label above section titles. Mono, generous tracking. ========================================================================= */ .eyebrow { display: inline-block; font-family: var(--font-family-mono); font-size: 11px; font-weight: var(--font-weight-semibold); letter-spacing: 0.08em; text-transform: uppercase; color: var(--color-scope-architect, var(--color-text-link)); margin: 0 0 var(--space-2); } /* ========================================================================= 14. Page-shell (.page__*) Standard report-page header used by renderPageShell() in playgrounds. eyebrow → h1 → optional lede → optional meta + verdict slot side-by-side. ========================================================================= */ .page__header { display: grid; grid-template-columns: 1fr auto; gap: var(--space-5); align-items: start; padding-block: var(--space-3) var(--space-4); margin-bottom: var(--space-5); border-bottom: 1px solid var(--color-border-subtle); } .page__header-main { min-width: 0; } .page__header-aside { display: flex; flex-direction: column; align-items: flex-end; gap: var(--space-2); } .page__eyebrow { display: inline-block; font-family: var(--font-family-mono); font-size: 11px; font-weight: var(--font-weight-semibold); letter-spacing: 0.08em; text-transform: uppercase; color: var(--color-scope-architect, var(--color-text-link)); margin: 0 0 var(--space-2); } .page__title { font-family: var(--font-family-sans); font-size: var(--font-size-3xl); font-weight: var(--font-weight-bold); letter-spacing: -0.02em; line-height: 1.15; color: var(--color-text-primary); margin: 0 0 var(--space-2); } .page__lede { font-size: var(--font-size-md); line-height: 1.55; color: var(--color-text-secondary); max-width: 70ch; margin: 0 0 var(--space-2); } .page__meta { font-family: var(--font-family-mono); font-size: 12px; color: var(--color-text-tertiary); display: flex; gap: var(--space-3); flex-wrap: wrap; } @media (max-width: 720px) { .page__header { grid-template-columns: 1fr; } .page__header-aside { align-items: flex-start; } } /* ========================================================================= 15. Key-stats grid (.key-stats / .key-stat) 2-5 column responsive grid of large-number metrics. Uses tabular-nums for visual alignment. Severity modifiers tint the value color. ========================================================================= */ .key-stats { display: grid; grid-template-columns: repeat(auto-fit, minmax(160px, 1fr)); gap: var(--space-4); padding: var(--space-4) var(--space-5); background: var(--color-bg-soft); border: 1px solid var(--color-border-subtle); border-radius: var(--radius-lg); margin-block: var(--space-4); } .key-stat { display: flex; flex-direction: column; gap: 4px; min-width: 0; } .key-stat__label { font-family: var(--font-family-mono); font-size: 11px; font-weight: var(--font-weight-semibold); letter-spacing: 0.08em; text-transform: uppercase; color: var(--color-text-tertiary); } .key-stat__value { font-family: var(--font-family-sans); font-size: var(--font-size-2xl); font-weight: var(--font-weight-bold); letter-spacing: -0.02em; font-variant-numeric: tabular-nums; color: var(--color-text-primary); line-height: 1.1; word-break: break-word; } .key-stat__hint { font-size: 12px; color: var(--color-text-tertiary); margin-top: 2px; } .key-stat--critical .key-stat__value { color: var(--color-severity-critical); } .key-stat--high .key-stat__value { color: var(--color-severity-high); } .key-stat--medium .key-stat__value { color: var(--color-severity-medium); } .key-stat--low .key-stat__value { color: var(--color-severity-low); } .key-stat--positive .key-stat__value { color: var(--color-state-success); } .key-stat--info .key-stat__value { color: var(--color-state-info); } /* ========================================================================= 16. Verdict-pill 5-band extension Extends existing .verdict-pill-lg (Tier 2) to all 5 severity bands + neutral n-a. Backward compatible — existing block/warning/allow keys remain unchanged. ========================================================================= */ .verdict-pill-lg[data-verdict="critical"], .verdict-pill-lg[data-verdict="extreme"] { background: var(--color-severity-critical); color: #fff; } .verdict-pill-lg[data-verdict="high"] { background: var(--color-severity-high); color: #fff; } .verdict-pill-lg[data-verdict="medium"] { background: var(--color-severity-medium); color: var(--color-severity-medium-on); } .verdict-pill-lg[data-verdict="low"] { background: var(--color-severity-low); color: #fff; } .verdict-pill-lg[data-verdict="positive"] { background: var(--color-state-success); color: #fff; } .verdict-pill-lg[data-verdict="n-a"], .verdict-pill-lg[data-verdict="info"], .verdict-pill-lg[data-verdict="neutral"] { background: var(--color-surface-sunken); color: var(--color-text-secondary); border: 1px solid var(--color-border-moderate); } /* ========================================================================= 17. Tab-component (.tab-list / .tab / .tab-panel) Generic tabbed interface. ARIA-paritet: role="tablist", role="tab", aria-current="true" for active. tab-panel is hidden via [hidden] attr. ========================================================================= */ .tab-list { display: flex; gap: var(--space-1); flex-wrap: wrap; padding: 4px; background: var(--color-bg-soft); border: 1px solid var(--color-border-subtle); border-radius: var(--radius-md); margin-bottom: var(--space-4); } .tab { appearance: none; border: 1px solid transparent; background: transparent; color: var(--color-text-secondary); font-family: var(--font-family-sans); font-size: var(--font-size-sm); font-weight: var(--font-weight-medium); padding: 6px var(--space-3); border-radius: var(--radius-sm); cursor: pointer; display: inline-flex; align-items: center; gap: 6px; transition: background var(--duration-fast), color var(--duration-fast); } .tab:hover { background: var(--color-surface-sunken); color: var(--color-text-primary); } .tab[aria-current="true"] { background: var(--color-surface); color: var(--color-text-primary); border-color: var(--color-border-subtle); box-shadow: var(--shadow-sm); } .tab:focus-visible { outline: none; box-shadow: var(--shadow-focus); } .tab__count { display: inline-flex; align-items: center; justify-content: center; min-width: 22px; padding: 0 6px; font-family: var(--font-family-mono); font-size: 11px; background: var(--color-surface-sunken); color: var(--color-text-tertiary); border-radius: 999px; } .tab[aria-current="true"] .tab__count { background: var(--color-bg-soft); color: var(--color-text-primary); } .tab-panel { padding-block: var(--space-3); } .tab-panel[hidden] { display: none; } /* ========================================================================= 18. Top-risks (.top-risks / .top-risk) Severity-ordered list of top risk items used by ROS/security renderers. Each row: rank dot - description - score column. Severity drives left-border. ========================================================================= */ .top-risks { display: flex; flex-direction: column; gap: var(--space-2); margin-block: var(--space-4); } .top-risks__heading { font-family: var(--font-family-mono); font-size: 11px; font-weight: var(--font-weight-semibold); letter-spacing: 0.08em; text-transform: uppercase; color: var(--color-text-tertiary); margin: 0 0 var(--space-1); } .top-risk { display: grid; grid-template-columns: 32px 1fr auto; gap: var(--space-3); align-items: center; padding: var(--space-3) var(--space-4); background: var(--color-surface); border: 1px solid var(--color-border-subtle); border-left: 4px solid var(--color-border-moderate); border-radius: var(--radius-md); } .top-risk[data-severity="critical"] { border-left-color: var(--color-severity-critical); } .top-risk[data-severity="high"] { border-left-color: var(--color-severity-high); } .top-risk[data-severity="medium"] { border-left-color: var(--color-severity-medium); } .top-risk[data-severity="low"] { border-left-color: var(--color-severity-low); } .top-risk__rank { font-family: var(--font-family-mono); font-size: var(--font-size-md); font-weight: var(--font-weight-bold); color: var(--color-text-tertiary); text-align: center; } .top-risk__desc { font-size: var(--font-size-md); line-height: 1.4; color: var(--color-text-primary); min-width: 0; } .top-risk__score { font-family: var(--font-family-mono); font-size: var(--font-size-sm); font-weight: var(--font-weight-bold); font-variant-numeric: tabular-nums; padding: 4px 10px; border-radius: var(--radius-sm); background: var(--color-bg-soft); color: var(--color-text-primary); white-space: nowrap; } .top-risk[data-severity="critical"] .top-risk__score { background: var(--color-severity-critical-soft); color: var(--color-severity-critical-on); } .top-risk[data-severity="high"] .top-risk__score { background: var(--color-severity-high-soft); color: var(--color-severity-high-on); } .top-risk[data-severity="medium"] .top-risk__score { background: var(--color-severity-medium-soft); color: var(--color-severity-medium-on); } .top-risk[data-severity="low"] .top-risk__score { background: var(--color-severity-low-soft); color: var(--color-severity-low-on); } /* ========================================================================= 19. Recommendation-card (.recommendation-card) Emphasized advisory callout. Severity-tinted background + bold label. Used by security/ROS recommendations and architecture-review next-actions. ========================================================================= */ .recommendation-card { display: grid; grid-template-columns: auto 1fr; gap: var(--space-3); align-items: start; padding: var(--space-4) var(--space-5); background: var(--color-bg-soft); border: 1px solid var(--color-border-subtle); border-left: 4px solid var(--color-state-info); border-radius: var(--radius-md); margin-block: var(--space-3); } .recommendation-card__label { font-family: var(--font-family-mono); font-size: 11px; font-weight: var(--font-weight-bold); letter-spacing: 0.08em; text-transform: uppercase; padding: 4px 10px; border-radius: var(--radius-sm); background: var(--color-state-info); color: #fff; white-space: nowrap; } .recommendation-card__body { font-size: var(--font-size-md); line-height: 1.55; color: var(--color-text-primary); } .recommendation-card[data-severity="critical"] { border-left-color: var(--color-severity-critical); } .recommendation-card[data-severity="critical"] .recommendation-card__label { background: var(--color-severity-critical); } .recommendation-card[data-severity="high"] { border-left-color: var(--color-severity-high); } .recommendation-card[data-severity="high"] .recommendation-card__label { background: var(--color-severity-high); } .recommendation-card[data-severity="medium"] { border-left-color: var(--color-severity-medium); } .recommendation-card[data-severity="medium"] .recommendation-card__label { background: var(--color-severity-medium); color: var(--color-severity-medium-on); } .recommendation-card[data-severity="low"] { border-left-color: var(--color-severity-low); } .recommendation-card[data-severity="low"] .recommendation-card__label { background: var(--color-severity-low); } .recommendation-card[data-severity="positive"] { border-left-color: var(--color-state-success); } .recommendation-card[data-severity="positive"] .recommendation-card__label { background: var(--color-state-success); } /* ========================================================================= 20. Card subcomponents (.card__*) Composable subcomponents extending the existing .card primitive (base.css). Use as:
...
...
========================================================================= */ .card__head { display: flex; align-items: flex-start; justify-content: space-between; gap: var(--space-3); margin-bottom: var(--space-2); } .card__title { font-family: var(--font-family-sans); font-size: var(--font-size-lg); font-weight: var(--font-weight-semibold); letter-spacing: -0.01em; color: var(--color-text-primary); margin: 0; line-height: 1.3; } .card__desc { font-size: var(--font-size-sm); line-height: 1.5; color: var(--color-text-secondary); margin: 0 0 var(--space-2); } .card__id { font-family: var(--font-family-mono); font-size: 12px; color: var(--color-text-tertiary); background: var(--color-surface-sunken); padding: 2px 8px; border-radius: var(--radius-sm); display: inline-block; } .card__meta { display: flex; gap: var(--space-2); align-items: center; flex-wrap: wrap; font-size: 12px; color: var(--color-text-tertiary); margin-top: var(--space-2); } .card__hint { font-family: var(--font-family-mono); font-size: 12px; color: var(--color-text-tertiary); margin-top: var(--space-1); } .card__actions { display: flex; gap: var(--space-2); align-items: center; flex-wrap: wrap; margin-top: var(--space-3); } .card__pill { display: inline-flex; align-items: center; padding: 2px 8px; font-family: var(--font-family-mono); font-size: 11px; font-weight: var(--font-weight-semibold); letter-spacing: 0.04em; text-transform: uppercase; background: var(--color-surface-sunken); color: var(--color-text-secondary); border-radius: 999px; white-space: nowrap; } /* Severity left-border modifier on cards */ .card--severity-critical { border-left: 4px solid var(--color-severity-critical); } .card--severity-high { border-left: 4px solid var(--color-severity-high); } .card--severity-medium { border-left: 4px solid var(--color-severity-medium); } .card--severity-low { border-left: 4px solid var(--color-severity-low); } .card--severity-positive { border-left: 4px solid var(--color-state-success); } .card--severity-info { border-left: 4px solid var(--color-state-info); } /* ========================================================================= 21. Form patterns (.field-row / .field-label / .field-help / etc) Standard form-field building blocks. Mirrors Aksel/Digdir conventions. ========================================================================= */ .field-row { display: flex; flex-direction: column; gap: 6px; } .field-row + .field-row { margin-top: var(--space-3); } .field-label { font-size: var(--font-size-sm); font-weight: var(--font-weight-medium); color: var(--color-text-primary); } .field-help { font-size: var(--font-size-xs); color: var(--color-text-tertiary); } .required-mark { color: var(--color-severity-critical); margin-left: 2px; font-weight: var(--font-weight-bold); } .multi-select { display: flex; flex-direction: column; gap: 4px; border: 0; padding: 0; margin: 0; } .checkbox-row { display: inline-flex; align-items: center; gap: 8px; cursor: pointer; font-size: var(--font-size-sm); padding: 4px 0; color: var(--color-text-primary); } .checkbox-row input { margin: 0; } .checkbox-row:hover { color: var(--color-text-link); } /* ========================================================================= 22. Section-spacing utility (.stack-lg / .stack-md / .stack-sm) Consistent vertical rhythm between major sections. ========================================================================= */ .stack-lg > * + * { margin-top: var(--space-8); } .stack-md > * + * { margin-top: var(--space-5); } .stack-sm > * + * { margin-top: var(--space-3); } /* ========================================================================= 23. Pyramide-tier-detail (.pyramide-tier-detail) Expandable details below a .pyramide visualization. Used by AI Act classification renderer to describe each tier's obligations. ========================================================================= */ .pyramide-tier-detail { background: var(--color-surface); border: 1px solid var(--color-border-subtle); border-radius: var(--radius-md); padding: var(--space-3) var(--space-4); margin-top: var(--space-2); } .pyramide-tier-detail summary { cursor: pointer; font-family: var(--font-family-sans); font-size: var(--font-size-md); font-weight: var(--font-weight-semibold); color: var(--color-text-primary); list-style: none; display: flex; align-items: center; gap: var(--space-2); } .pyramide-tier-detail summary::-webkit-details-marker { display: none; } .pyramide-tier-detail summary::before { content: "\25B8"; font-size: 11px; color: var(--color-text-tertiary); transition: transform var(--duration-fast); display: inline-block; } .pyramide-tier-detail[open] summary::before { transform: rotate(90deg); } .pyramide-tier-detail__body { font-size: var(--font-size-sm); line-height: 1.55; color: var(--color-text-secondary); margin-top: var(--space-2); padding-left: var(--space-3); } /* ========================================================================= 24. Scenario-card-grid (.scenario-card-grid / .scenario-card) Grid of scenario/option cards used by license, compare renderers. Each card: header (title + count) -> optional source line -> optional body. ========================================================================= */ .scenario-card-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); gap: var(--space-3); margin-block: var(--space-3); } .scenario-card { display: flex; flex-direction: column; gap: var(--space-2); padding: var(--space-4); background: var(--color-surface); border: 1px solid var(--color-border-subtle); border-radius: var(--radius-md); transition: border-color var(--duration-fast), box-shadow var(--duration-fast); } .scenario-card:hover { border-color: var(--color-border-moderate); box-shadow: var(--shadow-sm); } .scenario-card__head { display: flex; align-items: flex-start; justify-content: space-between; gap: var(--space-2); } .scenario-card__title { font-family: var(--font-family-sans); font-size: var(--font-size-md); font-weight: var(--font-weight-semibold); color: var(--color-text-primary); margin: 0; line-height: 1.3; } .scenario-card__count { display: inline-flex; align-items: center; justify-content: center; min-width: 24px; padding: 2px 8px; font-family: var(--font-family-mono); font-size: 11px; font-weight: var(--font-weight-bold); background: var(--color-bg-soft); color: var(--color-text-secondary); border-radius: 999px; } .scenario-card__source { font-family: var(--font-family-mono); font-size: 12px; color: var(--color-text-tertiary); } .scenario-card[data-status="winner"] { border-color: var(--color-state-success); background: var(--color-severity-low-soft); } .scenario-card[data-status="winner"] .scenario-card__count { background: var(--color-state-success); color: #fff; } /* ========================================================================= 25. App-shell utility (.app-shell) Centered max-width page wrapper. Hoisted from playgrounds - every plugin playground uses the same shell pattern. ========================================================================= */ .app-shell { max-width: 1200px; margin: 0 auto; padding: var(--space-6) var(--space-5); } .app-shell--wide { max-width: 1400px; } .app-shell--narrow { max-width: 880px; }