/* ========================================================================== Dark, minimal photography theme — shared by public site and admin. ========================================================================== */ :root { --bg: #0b0b0c; --bg-raise: #151517; --fg: #f4f4f2; --muted: #9a9a96; --line: #29292c; --danger: #e05b4d; --ok: #6fbf8f; --nav-h: 64px; } * { box-sizing: border-box; margin: 0; padding: 0; } html { scroll-behavior: smooth; } body { background: var(--bg); color: var(--fg); font-family: "Helvetica Neue", Helvetica, Arial, system-ui, sans-serif; font-size: 16px; line-height: 1.6; -webkit-font-smoothing: antialiased; } img { max-width: 100%; display: block; } a { color: inherit; text-decoration: none; } /* -------------------------------------------------------------------------- Public navigation — fixed, hides on scroll-down, returns on scroll-up -------------------------------------------------------------------------- */ .nav { position: fixed; inset: 0 0 auto 0; height: var(--nav-h); display: flex; align-items: center; justify-content: space-between; padding: 0 clamp(1.25rem, 4vw, 3rem); z-index: 100; background: linear-gradient(to bottom, rgba(0,0,0,.55), rgba(0,0,0,0)); transition: transform .35s ease, opacity .35s ease; } .nav.nav-hidden { transform: translateY(-100%); opacity: 0; pointer-events: none; } .nav-brand { font-size: 1.05rem; letter-spacing: .18em; text-transform: uppercase; font-weight: 500; } /* The public brand is the artist's name (user content): show it exactly as typed rather than force-uppercased, so characters like ß are not expanded to SS by the browser. Admin/login brand keeps the uppercase styling. */ .nav .nav-brand { text-transform: none; letter-spacing: .12em; } .nav-links { display: flex; gap: 2rem; } .nav-links a { font-size: .8rem; letter-spacing: .22em; text-transform: uppercase; color: var(--muted); transition: color .2s; } .nav-links a:hover, .nav-links a.active { color: var(--fg); } /* -------------------------------------------------------------------------- Landing page -------------------------------------------------------------------------- */ .hero { position: relative; height: 100svh; overflow: hidden; } .hero img { width: 100%; height: 100%; object-fit: cover; } .hero-placeholder { width: 100%; height: 100%; background: radial-gradient(120% 90% at 50% 20%, #1d1d21 0%, #0b0b0c 70%); } .hero-caption { position: absolute; inset: auto 0 0 0; padding: clamp(2rem, 8vh, 6rem) clamp(1.25rem, 4vw, 3rem); background: linear-gradient(to top, rgba(0,0,0,.65), rgba(0,0,0,0)); } .hero-caption h1 { font-size: clamp(2.2rem, 6vw, 4.5rem); font-weight: 300; letter-spacing: .12em; /* Artist name shown as typed (see .nav .nav-brand) so ß stays ß. */ } .hero-scroll-hint { position: absolute; bottom: 1.2rem; left: 50%; translate: -50% 0; color: rgba(255,255,255,.7); font-size: 1.4rem; animation: hint 2.2s ease-in-out infinite; } @keyframes hint { 0%, 100% { transform: translateY(0); opacity: .5; } 50% { transform: translateY(8px); opacity: 1; } } .intro { max-width: 42rem; margin: 0 auto; padding: clamp(4rem, 14vh, 9rem) 1.5rem; text-align: center; } .intro p { font-size: clamp(1.05rem, 1.6vw, 1.3rem); font-weight: 300; color: var(--fg); white-space: pre-line; line-height: 1.9; } .intro .cta { display: inline-block; margin-top: 3rem; padding: .9rem 2.6rem; border: 1px solid var(--fg); font-size: .8rem; letter-spacing: .25em; text-transform: uppercase; transition: background .25s, color .25s; } .intro .cta:hover { background: var(--fg); color: var(--bg); } /* -------------------------------------------------------------------------- Contact page — landing-style centered layout -------------------------------------------------------------------------- */ .contact { min-height: 100svh; display: flex; flex-direction: column; justify-content: center; } .contact-title { font-size: clamp(1.8rem, 5vw, 3.2rem); font-weight: 300; letter-spacing: .1em; margin-bottom: 1.4rem; } .contact-methods { margin-top: 2.6rem; display: flex; flex-direction: column; align-items: center; gap: 1rem; } .contact-methods a { font-size: 1.05rem; letter-spacing: .05em; color: var(--fg); border-bottom: 1px solid var(--line); padding-bottom: .2rem; transition: border-color .25s; } .contact-methods a:hover { border-color: var(--fg); } /* -------------------------------------------------------------------------- Prose — rendered Markdown for the legal pages (Impressum / Datenschutz) -------------------------------------------------------------------------- */ .prose { max-width: 46rem; font-weight: 300; } .prose h1, .prose h2, .prose h3 { font-weight: 400; letter-spacing: .04em; margin: 2rem 0 .8rem; } .prose h1 { font-size: 1.5rem; } .prose h2 { font-size: 1.2rem; } .prose h3 { font-size: 1.05rem; } .prose p { margin-bottom: 1rem; } .prose ul { margin: 0 0 1rem 1.3rem; } .prose li { margin-bottom: .35rem; } .prose a { text-decoration: underline; } .prose a:hover { color: var(--muted); } .prose-empty { color: var(--muted); } /* -------------------------------------------------------------------------- Showreel — one image per viewport, scroll snap -------------------------------------------------------------------------- */ body.reel-page { scroll-snap-type: y mandatory; } .reel-slide { height: 100svh; scroll-snap-align: start; scroll-snap-stop: always; display: flex; align-items: center; justify-content: center; background: #000; } .reel-slide img { max-width: 100%; max-height: 100svh; width: auto; height: auto; object-fit: contain; } .reel-empty { height: 100svh; display: grid; place-items: center; color: var(--muted); letter-spacing: .1em; } /* -------------------------------------------------------------------------- Gallery — password gate, thumbnail grid, lightbox -------------------------------------------------------------------------- */ .page { max-width: 1400px; margin: 0 auto; padding: calc(var(--nav-h) + 3rem) clamp(1rem, 3vw, 2.5rem) 4rem; } .page-title { font-weight: 300; letter-spacing: .1em; /* Gallery title is user content — shown as typed so ß stays ß. */ font-size: clamp(1.4rem, 3vw, 2.2rem); margin-bottom: .4rem; } .page-sub { color: var(--muted); font-size: .9rem; margin-bottom: 2.5rem; } .gate { min-height: 100svh; display: grid; place-items: center; padding: 1.5rem; } .gate-card { width: 100%; max-width: 24rem; text-align: center; } .gate-card h1 { font-weight: 300; letter-spacing: .12em; /* Gallery title is user content — shown as typed so ß stays ß. */ font-size: 1.4rem; margin-bottom: 1.8rem; } .grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(240px, 1fr)); gap: 6px; } .grid a { position: relative; aspect-ratio: 3 / 2; overflow: hidden; background: var(--bg-raise); } .grid img { width: 100%; height: 100%; object-fit: cover; transition: transform .4s ease, opacity .4s; opacity: .92; } .grid a:hover img { transform: scale(1.03); opacity: 1; } /* Lightbox */ .lightbox { position: fixed; inset: 0; z-index: 200; background: rgba(0,0,0,.96); display: none; align-items: center; justify-content: center; } .lightbox.open { display: flex; } .lightbox img { max-width: 96vw; max-height: 96svh; object-fit: contain; } .lightbox button { position: absolute; background: none; border: none; color: rgba(255,255,255,.75); font-size: 2rem; cursor: pointer; padding: 1rem; line-height: 1; transition: color .2s; } .lightbox button:hover { color: #fff; } .lb-close { top: .5rem; right: .8rem; } .lb-prev { left: .4rem; top: 50%; translate: 0 -50%; } .lb-next { right: .4rem; top: 50%; translate: 0 -50%; } .lb-count { position: absolute; bottom: 1rem; left: 50%; translate: -50% 0; color: var(--muted); font-size: .8rem; letter-spacing: .15em; } /* -------------------------------------------------------------------------- Footer -------------------------------------------------------------------------- */ .footer { padding: 2.5rem clamp(1.25rem, 4vw, 3rem); color: var(--muted); font-size: .75rem; letter-spacing: .15em; /* Contains the artist name — shown as typed so ß stays ß. */ text-align: center; } .footer-links { display: flex; justify-content: center; gap: 1.6rem; margin-bottom: 1rem; } .footer-links a { text-transform: uppercase; color: var(--muted); transition: color .2s; } .footer-links a:hover { color: var(--fg); } /* -------------------------------------------------------------------------- Forms (shared) -------------------------------------------------------------------------- */ label { display: block; font-size: .8rem; letter-spacing: .12em; text-transform: uppercase; color: var(--muted); margin: 1.1rem 0 .35rem; } input[type=text], input[type=password], input[type=date], input[type=number], textarea, select { width: 100%; padding: .7rem .9rem; background: var(--bg-raise); border: 1px solid var(--line); color: var(--fg); font: inherit; border-radius: 4px; } input:focus, textarea:focus { outline: 1px solid var(--muted); } /* Resolution picker: preset select, plus a custom px box when "Custom…" is chosen. The box is [hidden] otherwise, so the gap collapses on its own. */ .res-field { display: flex; gap: .6rem; } .res-field select { flex: 1; } .res-field input[type=number] { flex: 0 0 9rem; } textarea { min-height: 9rem; resize: vertical; } button, .btn { display: inline-block; margin-top: 1.4rem; padding: .75rem 1.8rem; background: var(--fg); color: var(--bg); border: none; font: inherit; font-size: .8rem; letter-spacing: .18em; text-transform: uppercase; cursor: pointer; border-radius: 4px; } .btn-ghost { background: none; color: var(--fg); border: 1px solid var(--line); } .btn-danger { background: var(--danger); color: #fff; } /* A download offered but not currently available: the gallery's archive is being rebuilt. Rendered as a with a title, so hovering explains why. */ .btn-disabled { opacity: .45; cursor: not-allowed; } /* Gallery heading row: title and subtitle on the left, download on the right. The subtitle carries the block's bottom margin, so the button sits flush with the title rather than adding space of its own. */ .page-head { display: flex; align-items: flex-start; justify-content: space-between; gap: 1.5rem; flex-wrap: wrap; } .page-action { margin-top: 0; flex-shrink: 0; } @media (max-width: 600px) { /* Too narrow to sit beside the title; give it the full width instead. */ .page-head { gap: 0; } .page-head .page-sub { margin-bottom: 1.2rem; } .page-action { width: 100%; text-align: center; margin-bottom: 2.5rem; } } /* Archive build progress in the backoffice. */ .archive-bar { height: 4px; background: var(--line); border-radius: 2px; overflow: hidden; margin-bottom: 1rem; } .archive-bar span { display: block; height: 100%; width: 0; background: var(--fg); transition: width .3s ease; } .flash { padding: .8rem 1.1rem; border-radius: 4px; margin-bottom: 1.5rem; font-size: .9rem; } .flash-ok { background: rgba(111,191,143,.12); border: 1px solid rgba(111,191,143,.4); color: var(--ok); } .flash-error { background: rgba(224,91,77,.12); border: 1px solid rgba(224,91,77,.4); color: var(--danger); } /* -------------------------------------------------------------------------- Admin -------------------------------------------------------------------------- */ body.admin { background: #101012; } .admin-nav { display: flex; align-items: center; justify-content: space-between; flex-wrap: wrap; gap: .8rem; padding: 1rem clamp(1rem, 3vw, 2rem); border-bottom: 1px solid var(--line); background: var(--bg); } .admin-nav .nav-links { flex-wrap: wrap; gap: 1.2rem; } .admin-main { max-width: 1000px; margin: 0 auto; padding: 2.5rem clamp(1rem, 3vw, 2rem) 5rem; } .admin-main h1 { font-weight: 400; font-size: 1.5rem; margin-bottom: 1.6rem; } .admin-main h2 { font-weight: 400; font-size: 1.1rem; margin: 2.2rem 0 1rem; } .card { background: var(--bg-raise); border: 1px solid var(--line); border-radius: 6px; padding: 1.5rem; margin-bottom: 1.5rem; } table { width: 100%; border-collapse: collapse; font-size: .92rem; } th, td { text-align: left; padding: .65rem .5rem; border-bottom: 1px solid var(--line); vertical-align: middle; } th { color: var(--muted); font-weight: 400; font-size: .75rem; letter-spacing: .12em; text-transform: uppercase; } .tag { display: inline-block; padding: .1rem .55rem; border-radius: 99px; font-size: .72rem; border: 1px solid var(--line); color: var(--muted); } .tag-lock { border-color: rgba(111,191,143,.5); color: var(--ok); } .tag-expired{ border-color: rgba(224,91,77,.5); color: var(--danger); } .thumb-row { display: flex; flex-wrap: wrap; gap: 10px; } .thumb-row figure { position: relative; width: 140px; } .thumb-row img { width: 140px; height: 100px; object-fit: cover; border-radius: 4px; background: #000; } .thumb-row figcaption { font-size: .7rem; color: var(--muted); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; margin-top: .25rem; } .thumb-row form { position: absolute; top: 4px; right: 4px; } .thumb-row form button { margin: 0; padding: .15rem .5rem; font-size: .7rem; background: rgba(0,0,0,.65); color: #fff; border-radius: 3px; } /* Upload queue */ .dropzone { border: 2px dashed var(--line); border-radius: 6px; padding: 2.5rem 1.5rem; text-align: center; color: var(--muted); cursor: pointer; transition: border-color .2s, color .2s; } .dropzone.drag { border-color: var(--fg); color: var(--fg); } .upload-list { margin-top: 1rem; font-size: .85rem; } .upload-item { display: flex; align-items: center; gap: .8rem; padding: .4rem 0; border-bottom: 1px solid var(--line); } .upload-item .name { flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } .upload-item .state { color: var(--muted); min-width: 90px; text-align: right; } .upload-item .state.done { color: var(--ok); } .upload-item .state.error { color: var(--danger); } .upload-item .bar { width: 120px; height: 4px; background: var(--line); border-radius: 2px; overflow: hidden; } .upload-item .bar i { display: block; height: 100%; width: 0; background: var(--fg); transition: width .2s; } .help { color: var(--muted); font-size: .85rem; margin-top: .5rem; } .login-wrap { min-height: 80svh; display: grid; place-items: center; padding: 1.5rem; } .login-card { width: 100%; max-width: 22rem; } .login-card h1 { text-align: center; font-weight: 300; letter-spacing: .15em; text-transform: uppercase; font-size: 1.2rem; }