spb/datacenterindex
Public
HTML 53.9%
TypeScript 44.5%
JavaScript 0.6%
SQL 0.5%
1@import "tailwindcss";23@custom-variant dark (&:where(.dark, .dark *));45/* ------------------------------------------------------------------------------------------6 DataCenterIndex — design tokens7 Near-monochrome: ink + warm graphite + paper. ONE accent (signal amber) for pipeline/emphasis.8 Semantic status scale is fixed and shared with the map (see lib/labels.ts).9 ------------------------------------------------------------------------------------------ */10@theme {11 --font-sans: var(--font-inter), ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;12 --font-mono: var(--font-jetbrains), ui-monospace, "JetBrains Mono", "SF Mono", Menlo, Consolas, monospace;1314 --color-paper: var(--paper);15 --color-surface: var(--surface);16 --color-surface-2: var(--surface-2);17 --color-surface-3: var(--surface-3);18 --color-ink: var(--ink);19 --color-ink-2: var(--ink-2);20 --color-ink-3: var(--ink-3);21 --color-ink-4: var(--ink-4);22 --color-hair: var(--hair);23 --color-hair-2: var(--hair-2);24 --color-accent: var(--accent);25 --color-accent-ink: var(--accent-ink);26 --color-accent-soft: var(--accent-soft);2728 --color-st-operational: var(--st-operational);29 --color-st-construction: var(--st-construction);30 --color-st-planned: var(--st-planned);31 --color-st-permitting: var(--st-permitting);32 --color-st-delayed: var(--st-delayed);33 --color-st-closed: var(--st-closed);34 --color-st-rumored: var(--st-rumored);35 --color-st-unknown: var(--st-unknown);3637 --color-ok: var(--ok);38 --color-warn: var(--warn);39 --color-danger: var(--danger);40 --color-info: var(--info);4142 --radius-xs: 2px;43 --radius-sm: 3px;44 --radius-md: 4px;4546 --animate-fade-in: fade-in 0.18s ease-out both;47 --animate-sheet-up: sheet-up 0.22s cubic-bezier(0.2, 0.8, 0.2, 1) both;48 --animate-sheet-side: sheet-side 0.22s cubic-bezier(0.2, 0.8, 0.2, 1) both;49 --animate-row-in: row-in 0.5s ease-out both;50 --animate-pulse-soft: pulse-soft 1.8s ease-in-out infinite;5152 @keyframes fade-in {53 from { opacity: 0; transform: translateY(-2px); }54 to { opacity: 1; transform: translateY(0); }55 }56 @keyframes sheet-up {57 from { opacity: 0; transform: translateY(24px); }58 to { opacity: 1; transform: translateY(0); }59 }60 @keyframes sheet-side {61 from { opacity: 0; transform: translateX(16px); }62 to { opacity: 1; transform: translateX(0); }63 }64 @keyframes row-in {65 from { background-color: color-mix(in oklab, var(--accent) 16%, transparent); }66 to { background-color: transparent; }67 }68 @keyframes pulse-soft {69 0%, 100% { opacity: 1; }70 50% { opacity: 0.45; }71 }72}7374:root {75 color-scheme: light;76 --paper: #f5f4f1;77 --surface: #ffffff;78 --surface-2: #efeeea;79 --surface-3: #e6e4df;80 --ink: #0b0f14;81 --ink-2: #3b4148;82 --ink-3: #666c73; /* 5.1:1 on paper (was #6b7178 = 4.49:1) */83 --ink-4: #9a9fa5; /* hint level only (placeholders, kbd, "/total") — below 4.5:1 by design */84 --hair: #e3e1dc;85 --hair-2: #c9c6bf;86 --accent: #c8541a;87 --accent-ink: #a3420f;88 --accent-soft: #f7e6dc;8990 /* status scale — validated (dataviz six checks): lightness-separated blue/violet, labels always accompany colour */91 --st-operational: #1f6b3a;92 --st-construction: #b87a0a;93 --st-planned: #5f8fc4;94 --st-permitting: #5b3f8f;95 --st-delayed: #a94a2a;96 --st-closed: #858a90;97 --st-rumored: #8f95a0;98 --st-unknown: #b3b6ba;99100 --ok: #1f6b3a;101 --warn: #b87a0a;102 --danger: #a94a2a;103 --info: #3f5b7a;104105 --map-water: #e9ecef;106}107108.dark {109 color-scheme: dark;110 --paper: #0b0f14;111 --surface: #10161d;112 --surface-2: #161d25;113 --surface-3: #1d252e;114 --ink: #eceae5;115 --ink-2: #b9b6ae;116 --ink-3: #8f959c; /* 6.2:1 on paper (was #858a90 = 5.4:1) */117 --ink-4: #7a8189; /* 4.8:1 on paper, 4.6:1 on surface (was #5b6168 = 3.1:1) */118 --hair: #1f272f;119 --hair-2: #2f3941;120 --accent: #e8763a;121 --accent-ink: #f08b52;122 --accent-soft: #2a1a10;123124 --st-operational: #3fa465;125 --st-construction: #d4962a;126 --st-planned: #7fb0e6;127 --st-permitting: #8a6bc9;128 --st-delayed: #d9704a;129 --st-closed: #6f757c;130 --st-rumored: #7b828c;131 --st-unknown: #4d545b;132133 --ok: #3fa465;134 --warn: #d4962a;135 --danger: #d9704a;136 --info: #7f9bb8;137}138139@layer base {140 html {141 -webkit-text-size-adjust: 100%;142 text-rendering: optimizeLegibility;143 scroll-padding-top: 4rem;144 }145 body {146 background: var(--paper);147 color: var(--ink);148 font-family: var(--font-sans);149 font-size: 14px;150 line-height: 1.45;151 font-feature-settings: "cv11", "ss01";152 overflow-x: hidden;153 }154 ::selection {155 background: color-mix(in oklab, var(--accent) 28%, transparent);156 }157 :focus-visible {158 outline: 2px solid var(--accent);159 outline-offset: 2px;160 border-radius: 2px;161 }162 button, [role="button"] {163 cursor: pointer;164 }165 a {166 text-underline-offset: 3px;167 }168 h1, h2, h3, h4 {169 letter-spacing: -0.01em;170 }171 table {172 border-collapse: separate;173 border-spacing: 0;174 }175 input::-webkit-search-cancel-button {176 -webkit-appearance: none;177 }178 @media (prefers-reduced-motion: reduce) {179 *, *::before, *::after {180 animation-duration: 0.01ms !important;181 animation-iteration-count: 1 !important;182 transition-duration: 0.01ms !important;183 scroll-behavior: auto !important;184 }185 }186}187188@utility tnum {189 font-variant-numeric: tabular-nums lining-nums;190}191@utility figure {192 font-family: var(--font-mono);193 font-variant-numeric: tabular-nums lining-nums;194 letter-spacing: -0.02em;195}196@utility no-scrollbar {197 scrollbar-width: none;198 &::-webkit-scrollbar { display: none; }199}200@utility hair-b {201 border-bottom: 1px solid var(--hair);202}203@utility safe-b {204 padding-bottom: env(safe-area-inset-bottom);205}206@utility label-caps {207 font-size: 10.5px;208 letter-spacing: 0.08em;209 text-transform: uppercase;210 color: var(--ink-3);211 font-weight: 500;212}213214/* Graticule texture for the home hero — thin lines, low contrast, never noisy. */215.graticule {216 background-image:217 linear-gradient(to right, color-mix(in oklab, var(--ink) 6%, transparent) 1px, transparent 1px),218 linear-gradient(to bottom, color-mix(in oklab, var(--ink) 6%, transparent) 1px, transparent 1px);219 background-size: 48px 48px;220 mask-image: linear-gradient(to bottom, rgba(0, 0, 0, 0.9), transparent 90%);221}222223/* Responsive table → compact two-line rows under 640 px (each cell carries data-label).224 Line 1: [data-primary] cell (name + meta) with the [data-lead] figure on the right.225 Line 2: the remaining cells wrap as "LABEL value" pairs. Cells hidden via `hidden sm:table-cell` stay hidden. */226.dci-table { width: 100%; }227.dci-table th { position: sticky; top: 0; z-index: 1; background: var(--surface); }228@media (max-width: 639.98px) {229 .dci-table.responsive thead { display: none; }230 .dci-table.responsive, .dci-table.responsive tbody { display: block; width: 100%; }231 .dci-table.responsive tr { display: flex; flex-wrap: wrap; align-items: baseline; column-gap: 12px; row-gap: 3px; width: 100%; border-bottom: 1px solid var(--hair); padding: 11px 0; min-height: 40px; }232 .dci-table.responsive td { order: 2; display: inline-flex; flex: 0 0 auto; align-items: baseline; gap: 5px; min-width: 0; max-width: 100%; padding: 0 !important; border: 0 !important; font-size: 12px; line-height: 1.35; text-align: left; }233 .dci-table.responsive td.hidden { display: none; }234 .dci-table.responsive td[data-label]::before { content: attr(data-label); color: var(--ink-3); font-family: var(--font-inter), ui-sans-serif, system-ui, sans-serif; font-size: 10px; letter-spacing: 0.06em; text-transform: uppercase; flex: 0 0 auto; }235 .dci-table.responsive td[data-primary] { order: 0; display: block; flex: 1 1 55%; font-size: 13px; line-height: 1.35; font-weight: 500; }236 .dci-table.responsive tr:not(:has(td[data-lead])) td[data-primary] { flex-basis: 100%; }237 .dci-table.responsive td[data-primary]::before { display: none; }238 .dci-table.responsive td[data-lead] { order: 1; flex: 1 0 auto; justify-content: flex-end; font-size: 13px; color: var(--ink); }239 .dci-table.responsive td[data-lead]::before { color: var(--ink-4); }240 /* Whole row = tap target for the primary RowLink (≥ 40 px); other links in the row stay clickable above it. */241 .dci-table.responsive tr { position: relative; }242 .dci-table.responsive td a { position: relative; z-index: 1; }243 .dci-table.responsive td[data-primary] a.dci-rowlink { position: static; }244 .dci-table.responsive td[data-primary] a.dci-rowlink::after { content: ""; position: absolute; inset: 0; z-index: 0; }245 /* Collapsed long lists: only the first 10 rows until "Show all N" (see <CollapsibleRows/>). */246 .dci-collapse[data-collapsed] tbody > tr:nth-child(n + 11),247 .dci-collapse[data-collapsed] > :is(ol, ul) > li:nth-child(n + 11) { display: none; }248}249250/* Dual range slider — two overlaid native inputs, only the thumbs are visible. */251.dual-range { pointer-events: none; }252.dual-range::-webkit-slider-runnable-track { background: transparent; height: 2px; }253.dual-range::-moz-range-track { background: transparent; height: 2px; }254.dual-range::-webkit-slider-thumb { pointer-events: auto; -webkit-appearance: none; appearance: none; width: 22px; height: 22px; margin-top: -10px; border-radius: 50%; background: var(--surface); border: 2px solid var(--ink); cursor: grab; }255.dual-range::-moz-range-thumb { pointer-events: auto; width: 18px; height: 18px; border-radius: 50%; background: var(--surface); border: 2px solid var(--ink); cursor: grab; }256.dual-range:focus-visible::-webkit-slider-thumb { outline: 2px solid var(--accent); outline-offset: 2px; }257258/* MapLibre overrides — keep controls on brand and small. */259.maplibregl-ctrl-group { border-radius: 3px !important; box-shadow: none !important; border: 1px solid var(--hair-2); background: var(--surface) !important; }260.maplibregl-ctrl-group button { width: 32px !important; height: 32px !important; }261@media (max-width: 767.98px) { .maplibregl-ctrl-group button { width: 40px !important; height: 40px !important; } .maplibregl-ctrl-group button .maplibregl-ctrl-icon { background-size: 20px; } }262.dark .maplibregl-ctrl-group button .maplibregl-ctrl-icon { filter: invert(1); }263.maplibregl-ctrl-attrib { font-size: 10px !important; background: color-mix(in oklab, var(--surface) 85%, transparent) !important; color: var(--ink-3) !important; }264.maplibregl-ctrl-attrib a { color: var(--ink-2) !important; }265.maplibregl-canvas:focus { outline: none; }266/* Keep MapLibre controls above the fixed mobile bottom nav. */267@media (max-width: 767.98px) {268 body:not([data-hide-mobile-nav]) .maplibregl-ctrl-bottom-right,269 body:not([data-hide-mobile-nav]) .maplibregl-ctrl-bottom-left { bottom: calc(3.5rem + env(safe-area-inset-bottom)); }270}271