T-HUB/apps/web/src/app/globals.css
hacklab c423f172d0 style: light theme and hand-inked logo matching acampada26s.net
The previous pass kept the dark base and the red icons, which did not
read as the acampada. Now:

- Light theme: white page, black ink and borders, black buttons with a
  hard neon offset shadow, neon for focus and the active nav item;
  h1/h2 in Anton with the stepped neon shadow of the site headings.
- Nav, empty-state, spinner and pattern assets in black; platform icons
  keep their dark disc with a neon stroke.
- New mark: three dome tents wired from their doors into a switch with
  an antenna, drawn in the inked style of the acampada logo (curved
  poles, ball ends, hatching) over a neon offset copy. LogoMark renders
  it inline; visible product name is T-HUB.
- docs/brand: t-hub.svg and a lockup with the Anton wordmark converted
  to outlines so it renders without the font.
- Public submission page moved to the light palette.

Checked with headless Chromium screenshots (offline sample data) on
desktop and mobile.
2026-10-15 14:40:02 +02:00

225 lines
7.4 KiB
CSS
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

@import "tailwindcss";
/* Anton (SIL OFL 1.1, public/fonts/Anton-OFL.txt) — same title face as acampada26s.net. */
@font-face {
font-family: "Anton";
src: url("/fonts/anton.woff2") format("woff2");
font-display: swap;
}
@theme {
/* T-HUB: the acampada26s.net palette. White page, black ink and borders,
neon #00e5ff for hover, focus and the offset shadows. */
--color-bg: #fff;
--color-surface: #fff;
--color-surface-2: #f2f2f2;
--color-border: #000;
--color-border-subtle: #d4d4d4;
--color-text: #000;
--color-text-dim: #333;
--color-text-faint: #666;
--color-accent: #000;
--color-accent-hover: #222;
--color-accent-dim: rgb(0 229 255 / 0.28);
--color-neon: #00e5ff;
--color-live: #007a3d;
--color-warn: #8a5a00;
--color-danger: #c4001a;
--color-added: #007a3d;
--color-removed: #c4001a;
--font-sans: ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
--font-mono: ui-monospace, "SF Mono", Menlo, monospace;
--font-title: "Anton", Impact, "Arial Narrow", sans-serif;
--radius-sm: 0.375rem;
--radius-md: 0.5rem;
--radius-lg: 0.75rem;
--text-2xs: 0.6875rem;
--text-xs: 0.75rem;
--text-sm: 0.8125rem;
--text-base: 0.875rem;
--text-lg: 1rem;
--mobile-tab-height: 76px;
--mobile-fab-size: 64px;
--mobile-sheet-radius: 28px;
--mobile-safe-bottom: env(safe-area-inset-bottom, 0px);
}
@theme inline {
--color-brand: var(--color-accent);
}
html {
color-scheme: light;
}
body {
background: var(--color-bg);
color: var(--color-text);
font-family: var(--font-sans);
font-size: var(--text-base);
-webkit-font-smoothing: antialiased;
}
html, body { max-width: 100%; }
/* Titles as on acampada26s.net: Anton, uppercase, hard neon offset. */
h1, h2 {
font-family: var(--font-title);
font-weight: 400;
text-transform: uppercase;
letter-spacing: 0.01em;
}
h1 {
font-size: 1.75rem;
line-height: 1.05;
text-shadow: 0.01em 0.01em 0 var(--color-neon), 0.02em 0.02em 0 var(--color-neon), 0.03em 0.03em 0 var(--color-neon), 0.04em 0.04em 0 var(--color-neon);
}
/* Buttons as on acampada26s.net: hard offset shadow, neon on hover. */
button.bg-accent, a.bg-accent {
box-shadow: 0 3px 0 var(--color-neon);
}
button.bg-accent:hover, a.bg-accent:hover, button.bg-accent:focus-visible, a.bg-accent:focus-visible {
box-shadow: 0 5px 0 var(--color-neon);
}
:focus-visible {
outline-color: var(--color-neon);
}
@media (max-width: 1023px) {
body { overflow-x: hidden; }
[data-mobile-main] :is(button, a[href], input, select, textarea, [role="tab"]) {
min-height: 44px;
}
[data-mobile-main] :is(button, a[href], [role="tab"]) {
min-width: 44px;
}
[data-mobile-main] p a[href] { display: inline-flex; align-items: center; }
[data-mobile-main] .mobile-stack-table,
[data-mobile-main] .mobile-stack-table tbody,
[data-mobile-main] .mobile-stack-table tr,
[data-mobile-main] .mobile-stack-table td { display: block; width: 100%; min-width: 0; }
[data-mobile-main] .mobile-stack-table thead { display: none; }
[data-mobile-main] .mobile-stack-table tr { padding: 8px 0; }
[data-mobile-main] .mobile-stack-table td { overflow-wrap: anywhere; }
[data-mobile-main] .mobile-stack-table td > * { max-width: 100%; }
}
/* ---------------------------------------------------------------------------
Phone tier (≤640px) — native feel, touch targets, safe areas, overflow.
Scoped globally (body-wide) rather than to [data-mobile-main] because the
auth screens (/login, /signup, /join, /submit, /oidc) and the body-portal
sheets render outside the main shell and were getting none of this.
These rules are unlayered, so they outrank Tailwind's `@layer utilities`
without needing !important.
--------------------------------------------------------------------------- */
@media (max-width: 640px) {
/* -- Native feel: no tap highlight flash, no double-tap-zoom delay on
controls (pinch zoom stays available — `manipulation` only disables
the double-tap gesture), no iOS landscape text inflation, no document
rubber-band behind the app shell. -- */
html {
-webkit-text-size-adjust: 100%;
text-size-adjust: 100%;
overscroll-behavior: none;
overflow-x: hidden;
}
body {
max-width: 100%;
overflow-x: hidden;
-webkit-tap-highlight-color: transparent;
}
body :where(button, a[href], [role="tab"], [role="button"], [role="switch"]) {
touch-action: manipulation;
}
/* -- ≥44px touch targets for buttons / icon-buttons (glyph buttons here are
plain <button>, bottom-nav tabs are <a>, segmented control is role=tab,
sheet drag handle is role=button). min-width is limited to controls that
are already box-shaped so inline text links keep their flow shape. -- */
body :where(button, a[href], [role="tab"], [role="button"], [role="switch"]) {
min-height: 44px;
}
body :where(nav button, nav a[href], [role="tab"]) {
min-width: 44px;
}
/* -- 16px minimum on text-entry controls: iOS Safari auto-zooms the viewport
on focus whenever the field's computed font-size is under 16px, which
reads as janky/non-native. Non-text inputs excluded (their size is
visual, not textual). -- */
body :where(
input:not([type="checkbox"]):not([type="radio"]):not([type="range"]):not([type="file"]):not([type="button"]):not([type="submit"]):not([type="reset"]),
select,
textarea
) {
font-size: 16px;
}
/* -- Icon sizing. Icons size via width/height attributes from React props,
not a CSS variable or utility class — but HTML sizing attributes are
presentational hints, so author CSS still wins without touching TSX.
Bottom-nav glyph: 24px → 22px (target band 20–22px; top of band keeps
it clearest at phone density). Inline SVG icons: ≥16px floor so the
14px spinners and 11px arrow glyphs stop rendering sub-legibly. -- */
nav[aria-label="Primary navigation"] img {
width: 22px;
height: 22px;
}
body :where(svg) {
min-width: 16px;
min-height: 16px;
}
/* -- Safe areas. Bottom is already covered app-wide via --mobile-safe-bottom
(bottom nav, sheets, compose's fixed action bar). This adds the other
three edges on the shell column that holds top bar + main + bottom nav
— the notch/home-indicator sides that only bite in landscape.
max() keeps the value at 0 on devices without insets, and degrades to
no padding at all on browsers without :has(). -- */
:has(> main[data-mobile-main]) {
padding-top: max(0px, env(safe-area-inset-top, 0px));
padding-left: max(0px, env(safe-area-inset-left, 0px));
padding-right: max(0px, env(safe-area-inset-right, 0px));
}
/* -- Horizontal overflow guards: belt-and-braces on the scroller plus a
cap on replaced media, the classic cause of stray phone scroll. -- */
main[data-mobile-main] {
max-width: 100%;
}
body :where(img, video, canvas, iframe, svg) {
max-width: 100%;
}
}
::selection {
background: var(--color-accent-dim);
}
:focus-visible {
outline: 2px solid var(--color-accent);
outline-offset: 1px;
}
@media (prefers-reduced-motion: reduce) {
*,
*::before,
*::after {
transition-duration: 0.01ms !important;
animation-duration: 0.01ms !important;
}
}
.scrollbar-thin::-webkit-scrollbar {
width: 6px;
height: 6px;
}
.scrollbar-thin::-webkit-scrollbar-thumb {
background: var(--color-border);
border-radius: 3px;
}