/** * History timeline — scoped under .ngu-tl. * * Everything themeable is a custom property with a fallback, so rewiring to the * site tokens is a one-block edit at the top. Typefaces are deliberately not * set: the timeline inherits the page's type and only controls scale, weight * and tracking. */ .ngu-tl { /* Defaults match the site palette; History.tsx overrides accent and surface per section so the rail sits on the right background. */ --tl-ink: #16343a; --tl-muted: #4a6b72; --tl-faint: #8aa7ad; --tl-rail: #cfe4e8; --tl-surface: #ffffff; --tl-accent: #138ba0; --tl-accent-soft: color-mix(in srgb, var(--tl-accent) 12%, transparent); --tl-gutter: 5rem; --tl-rail-x: 1.75rem; --tl-rail-w: 2px; color: var(--tl-ink); } @media (max-width: 640px) { .ngu-tl { --tl-gutter: 3rem; --tl-rail-x: 1rem; } } /* ——— Decade block ——————————————————————————————————————————————— */ .ngu-tl__decade { position: relative; } /* The rail. One per decade block so the pre-program run can change style without breaking the line's continuity. */ .ngu-tl__decade::before { content: ''; position: absolute; top: 0; bottom: 0; left: var(--tl-rail-x); width: var(--tl-rail-w); background: var(--tl-rail); } .ngu-tl__decade--pre::before { background: none; border-left: var(--tl-rail-w) dashed var(--tl-rail); opacity: 0.7; } /* Last decade fades out rather than stopping dead. */ .ngu-tl__decade:last-child::before { bottom: 2rem; mask-image: linear-gradient(to bottom, #000 60%, transparent); } .ngu-tl__decade--pre { color: var(--tl-muted); } /* ——— Decade header ——————————————————————————————————————————————— */ .ngu-tl__decadeHead { position: relative; display: grid; grid-template-columns: var(--tl-gutter) minmax(0, 1fr); align-items: start; padding-block: 3.5rem 1.75rem; } .ngu-tl__decade:first-child .ngu-tl__decadeHead { padding-block-start: 0.5rem; } /* Numeral breaks the rail. */ .ngu-tl__decadeNum { position: relative; z-index: 1; margin-left: calc(var(--tl-rail-x) * -1 + 0.125rem); padding-block: 0.35rem; background: var(--tl-surface); font-size: 0.9375rem; font-weight: 650; font-variant-numeric: tabular-nums; letter-spacing: 0.01em; line-height: 1.1; writing-mode: vertical-rl; text-orientation: sideways; color: var(--tl-accent); } .ngu-tl__decade--pre .ngu-tl__decadeNum { color: var(--tl-faint); } .ngu-tl__decadeTitle { font-size: clamp(1.5rem, 1.1rem + 1.6vw, 2.125rem); font-weight: 600; line-height: 1.12; letter-spacing: -0.018em; margin: 0; max-width: 22ch; } .ngu-tl__decadeTagline { margin: 0.5rem 0 0; font-size: 1.0625rem; line-height: 1.5; color: var(--tl-muted); max-width: 54ch; } .ngu-tl__decadeBlurb { margin: 0.875rem 0 0; font-size: 0.9375rem; line-height: 1.65; color: var(--tl-muted); max-width: 62ch; } .ngu-tl__gapNote { margin: 1rem 0 0; display: inline-flex; align-items: center; gap: 0.5rem; padding: 0.375rem 0.75rem; border: 1px dashed var(--tl-rail); border-radius: 999px; font-size: 0.8125rem; color: var(--tl-faint); } /* ——— Year node ———————————————————————————————————————————————— */ .ngu-tl__year { position: relative; } .ngu-tl__yearBtn { position: relative; z-index: 1; display: grid; grid-template-columns: var(--tl-gutter) minmax(0, 1fr) auto; align-items: center; width: 100%; padding-block: 0.6875rem; background: none; border: 0; text-align: left; cursor: pointer; color: inherit; font: inherit; border-radius: 0.375rem; } .ngu-tl__yearBtn:hover .ngu-tl__yearLabel { color: var(--tl-accent); } .ngu-tl__yearBtn:focus-visible { outline: 2px solid var(--tl-accent); outline-offset: 2px; } /* Dot sits on the rail; --tl-dot is set inline from the year's item count, so scrolling the page gives you the organization's density at a glance. */ .ngu-tl__dot { position: relative; justify-self: start; margin-left: calc(var(--tl-rail-x) - (var(--tl-dot, 8px) / 2) + (var(--tl-rail-w) / 2)); width: var(--tl-dot, 8px); height: var(--tl-dot, 8px); border-radius: 50%; background: var(--tl-rail); box-shadow: 0 0 0 4px var(--tl-surface); transition: background-color 140ms ease, transform 140ms ease; } .ngu-tl__yearBtn:hover .ngu-tl__dot { background: var(--tl-accent); } .ngu-tl__year--featured .ngu-tl__dot { background: var(--tl-accent); } .ngu-tl__year--featured .ngu-tl__dot::after { content: ''; position: absolute; inset: -5px; border: 1.5px solid var(--tl-accent); border-radius: 50%; opacity: 0.45; } .ngu-tl__year--open .ngu-tl__dot { background: var(--tl-accent); transform: scale(1.15); } .ngu-tl__decade--pre .ngu-tl__dot { background: var(--tl-surface); border: 1.5px solid var(--tl-rail); } .ngu-tl__yearLabel { font-size: 1.125rem; font-weight: 550; font-variant-numeric: tabular-nums; letter-spacing: -0.01em; transition: color 140ms ease; } .ngu-tl__yearCount { font-size: 0.8125rem; font-variant-numeric: tabular-nums; color: var(--tl-faint); padding-right: 0.25rem; } .ngu-tl__year--empty .ngu-tl__yearLabel { color: var(--tl-faint); font-weight: 450; } /* ——— Expanded panel ——————————————————————————————————————————— */ .ngu-tl__panel { padding: 0.25rem 0 1.5rem var(--tl-gutter); animation: ngu-tl-reveal 220ms cubic-bezier(0.2, 0.7, 0.3, 1) both; } @keyframes ngu-tl-reveal { from { opacity: 0; transform: translateY(-4px); } } .ngu-tl__month { margin-top: 1.5rem; } .ngu-tl__month:first-child { margin-top: 0.5rem; } .ngu-tl__monthLabel { display: flex; align-items: center; gap: 0.75rem; margin: 0 0 0.625rem; font-size: 0.8125rem; font-weight: 550; color: var(--tl-muted); } .ngu-tl__monthLabel::after { content: ''; flex: 1; height: 1px; background: var(--tl-rail); opacity: 0.6; } .ngu-tl__undated .ngu-tl__monthLabel { font-style: italic; font-weight: 450; color: var(--tl-faint); } .ngu-tl__list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 0.125rem; } /* ——— Entry ————————————————————————————————————————————————————— */ .ngu-tl__entry { display: grid; grid-template-columns: 2.75rem minmax(0, 1fr); gap: 0.75rem; padding: 0.5rem 0.75rem 0.5rem 0; border-radius: 0.5rem; text-decoration: none; color: inherit; } a.ngu-tl__entry:hover { background: var(--tl-accent-soft); } a.ngu-tl__entry:focus-visible { outline: 2px solid var(--tl-accent); outline-offset: 1px; } .ngu-tl__entryDay { font-size: 0.8125rem; font-variant-numeric: tabular-nums; color: var(--tl-faint); padding-top: 0.1875rem; text-align: right; } .ngu-tl__entryTitle { display: block; font-size: 0.9375rem; font-weight: 500; line-height: 1.45; } a.ngu-tl__entry:hover .ngu-tl__entryTitle { color: var(--tl-accent); } .ngu-tl__entryMeta { display: block; margin-top: 0.125rem; font-size: 0.8125rem; color: var(--tl-muted); } .ngu-tl__entryBlurb { margin: 0.375rem 0 0; font-size: 0.875rem; line-height: 1.6; color: var(--tl-muted); max-width: 64ch; } /* Kind marker: a shape, not a colored pill, so a screenful of entries stays calm and the type still carries the hierarchy. */ .ngu-tl__kind { display: inline-block; width: 0.5rem; height: 0.5rem; margin-right: 0.5rem; vertical-align: 0.0625rem; background: var(--tl-faint); } .ngu-tl__kind--milestone { border-radius: 50%; background: var(--tl-accent); } .ngu-tl__kind--event { border-radius: 1px; } .ngu-tl__kind--award { clip-path: polygon(50% 0, 100% 50%, 50% 100%, 0 50%); } .ngu-tl__kind--person { border-radius: 50%; background: none; box-shadow: inset 0 0 0 1.5px var(--tl-faint); } /* ——— Featured entries ————————————————————————————————————————— */ .ngu-tl__featured { display: flex; flex-direction: column; gap: 0.75rem; margin-bottom: 0.5rem; } .ngu-tl__entry--featured { grid-template-columns: minmax(0, 1fr); padding: 1rem 1.125rem; border-left: 2px solid var(--tl-accent); background: var(--tl-accent-soft); border-radius: 0 0.5rem 0.5rem 0; } .ngu-tl__entry--featured .ngu-tl__entryTitle { font-size: 1.0625rem; font-weight: 600; letter-spacing: -0.008em; } .ngu-tl__entry--featured .ngu-tl__entryDay { text-align: left; padding: 0 0 0.25rem; } a.ngu-tl__entry--featured:hover { background: color-mix(in srgb, var(--tl-accent) 18%, transparent); } /* ——— Empty state ——————————————————————————————————————————————— */ .ngu-tl__empty { padding: 0.5rem 0 1.25rem var(--tl-gutter); font-size: 0.875rem; color: var(--tl-faint); } @media (prefers-reduced-motion: reduce) { .ngu-tl *, .ngu-tl *::before, .ngu-tl *::after { animation-duration: 0.01ms !important; transition-duration: 0.01ms !important; } } /* ——— Toolbar + utilities ————————————————————————————————————— */ .ngu-tl__toolbar { display: flex; justify-content: flex-end; padding-bottom: 1rem; } .ngu-tl__toolbarBtn { padding: 0.375rem 0.75rem; border: 1px solid var(--tl-rail); border-radius: 999px; background: none; color: var(--tl-muted); font: inherit; font-size: 0.8125rem; cursor: pointer; transition: color 140ms ease, border-color 140ms ease; } .ngu-tl__toolbarBtn:hover { color: var(--tl-accent); border-color: var(--tl-accent); } .ngu-tl__toolbarBtn:focus-visible { outline: 2px solid var(--tl-accent); outline-offset: 2px; } .ngu-tl__emptyState { padding: 3rem 0; color: var(--tl-muted); font-size: 0.9375rem; } .ngu-tl__srOnly { position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0; } /* ——— Upcoming block —————————————————————————————————————————— Opens upward: the toggle is first in the DOM, column-reverse puts the list above it. Faded because none of it has happened yet. */ .ngu-tl__upcoming { position: relative; display: flex; flex-direction: column-reverse; padding-bottom: 0.5rem; } .ngu-tl__upcoming::before { content: ''; position: absolute; top: 1.25rem; bottom: 0; left: var(--tl-rail-x); border-left: var(--tl-rail-w) dashed var(--tl-rail); } .ngu-tl__upcomingBtn { position: relative; z-index: 1; display: grid; grid-template-columns: var(--tl-gutter) minmax(0, 1fr) auto; align-items: center; width: 100%; padding-block: 0.75rem; background: none; border: 0; font: inherit; color: var(--tl-muted); text-align: left; cursor: pointer; } .ngu-tl__upcomingBtn:hover { color: var(--tl-accent); } .ngu-tl__upcomingBtn:focus-visible { outline: 2px solid var(--tl-accent); outline-offset: 2px; border-radius: 0.375rem; } .ngu-tl__upcomingDot { justify-self: start; margin-left: calc(var(--tl-rail-x) - 4px + (var(--tl-rail-w) / 2)); width: 8px; height: 8px; border-radius: 50%; border: 1.5px dashed var(--tl-accent); box-shadow: 0 0 0 4px var(--tl-surface); } .ngu-tl__upcomingLabel { font-size: 0.875rem; } .ngu-tl__chevron { font-size: 0.75rem; padding-right: 0.25rem; } /* Everything above the toggle is provisional, and reads that way. */ .ngu-tl__upcomingList { opacity: 0.62; animation: ngu-tl-rise 240ms cubic-bezier(0.2, 0.7, 0.3, 1) both; } .ngu-tl__upcomingList:hover, .ngu-tl__upcomingList:focus-within { opacity: 1; } .ngu-tl__upcomingList .ngu-tl__dot { background: var(--tl-surface); border: 1.5px dashed var(--tl-accent); } @keyframes ngu-tl-rise { from { opacity: 0; transform: translateY(8px); } } /* ——— Event / org / award logo ————————————————————————————————— */ .ngu-tl__logo { display: inline-block; width: 1.125rem; height: 1.125rem; margin-right: 0.5rem; vertical-align: -0.1875rem; object-fit: contain; border-radius: 2px; } .ngu-tl__entry--featured .ngu-tl__logo { width: 1.5rem; height: 1.5rem; vertical-align: -0.3125rem; } /* ——— People roster ——————————————————————————————————————————— */ .ngu-tl__entryWrap { display: block; } .ngu-tl__roster { padding: 0.125rem 0 0.5rem 3.5rem; } .ngu-tl__roster--featured { padding: 0.5rem 1.125rem 1rem; border-left: 2px solid var(--tl-accent); background: var(--tl-accent-soft); margin-top: -0.5rem; border-radius: 0 0 0.5rem 0; } .ngu-tl__rosterTeam { display: block; margin-bottom: 0.5rem; font-size: 0.75rem; color: var(--tl-faint); } .ngu-tl__people { display: flex; flex-wrap: wrap; gap: 0.375rem 1rem; list-style: none; margin: 0; padding: 0; } .ngu-tl__person { display: flex; align-items: center; gap: 0.5rem; } .ngu-tl__personPhoto { width: 1.75rem; height: 1.75rem; border-radius: 50%; object-fit: cover; background: var(--tl-accent-soft); flex: none; } .ngu-tl__personPhoto--blank { display: grid; place-items: center; font-size: 0.625rem; font-weight: 600; letter-spacing: 0.02em; color: var(--tl-accent); } .ngu-tl__personName { font-size: 0.8125rem; line-height: 1.25; } .ngu-tl__personTitle { display: block; font-size: 0.6875rem; color: var(--tl-faint); } /* ——— Kind markers, continued ————————————————————————————————— */ .ngu-tl__kind--organization { border-radius: 2px; background: none; box-shadow: inset 0 0 0 1.5px var(--tl-faint); } .ngu-tl__kind--people { border-radius: 50%; background: none; box-shadow: inset 0 0 0 1.5px var(--tl-faint); } .ngu-tl__entryBody { display: block; min-width: 0; }