/* site/assets/site.css
 * The layout every Kanzlei shares. Colours come only from brand.css, which the
 * build writes from kanzlei.json (--ink, --accent, --ground, --muted, --paper),
 * so this file carries no Kanzlei fact (CLAUDE.md rule 2), and kanzlei.mjs has
 * already checked each pairing used here against WCAG AA.
 * Mobile first: the base rules are the phone, one breakpoint widens them. */

/* Type: IBM Plex Sans and IBM Plex Serif, SIL Open Font Licence 1.1, served from
 * this origin only. ⚠ NEVER load a font from Google Fonts or any other host: the
 * Landgericht München I held in January 2022 that fetching a Google font from
 * Google's servers without consent breaks the DSGVO, and a third-party request
 * would also cost this site its consent-free position (ADR-0005).
 * The files are the Latin subsets, three faces, about 67 KB in total.
 * tests/fonts.test.mjs fails if a face is missing, unused or fetched elsewhere. */
@font-face {
  font-family: "IBM Plex Sans";
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url("fonts/ibm-plex-sans-latin-400-normal.woff2") format("woff2");
}

@font-face {
  font-family: "IBM Plex Sans";
  font-style: normal;
  font-weight: 600;
  font-display: swap;
  src: url("fonts/ibm-plex-sans-latin-600-normal.woff2") format("woff2");
}

@font-face {
  font-family: "IBM Plex Serif";
  font-style: normal;
  font-weight: 600;
  font-display: swap;
  src: url("fonts/ibm-plex-serif-latin-600-normal.woff2") format("woff2");
}

:root {
  --font-sans: "IBM Plex Sans", system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
  --font-serif: "IBM Plex Serif", Georgia, "Times New Roman", serif;
  /* One line of running text, 60 to 75 characters (DESIGN_DIRECTION 4.4). Every
     column of prose is held to it; only grids are allowed to be wider. */
  --measure: 34rem;
  /* The vertical rhythm: one value, so bands cannot drift apart. */
  --band: clamp(3rem, 7vw, 5.5rem);
}

*,
*::before,
*::after {
  box-sizing: border-box;
}

html {
  -webkit-text-size-adjust: 100%;
}

body {
  margin: 0;
  background: var(--paper);
  color: var(--ink);
  font-family: var(--font-sans);
  font-size: 1.125rem;
  line-height: 1.6;
  hyphens: auto;
  overflow-wrap: break-word;
}

.wrap {
  max-width: 72rem;
  margin: 0 auto;
  padding: 0 1rem;
}

.narrow {
  max-width: 46rem;
}

/* Running text never runs wider than one comfortable line, whatever holds it. */
.prose > p,
.prose > ul,
.prose > ol,
.narrow > p,
.narrow > ul,
.narrow > ol {
  max-width: var(--measure);
}

h1,
h2,
h3 {
  line-height: 1.2;
  font-weight: 600;
  color: var(--ink);
}

/* The page title is the serif, the section headings stay in the sans: one
   voice for what the page is, another for how it is organised. */
h1 {
  font-family: var(--font-serif);
  font-size: clamp(1.9rem, 5vw, 3rem);
  letter-spacing: -0.01em;
  /* ⚠ MEASURED, NOT GUESSED: "Wohnungseigentumsrecht" is 12.9em wide in Plex
     Serif 600. Every width limit on a heading must stay above that, or the
     browser breaks the word mid-letter with no hyphen ("Wohnungseigentumsrec /
     ht", seen on the draft, 2026-09-21). 16em is about two lines of a title and
     still holds the word whole. */
  max-width: 16em;
  margin: 0 0 1rem;
}

/* Hyphenation belongs in running text, not in display type: body copy keeps it
   (German compounds need it in a narrow column), headings and the lead do not.
   Below the breakpoint the headings get it back, because Wohnungseigentumsrecht
   does not fit on a phone otherwise. */
h1,
h2,
h3,
.lead,
.brand-name,
.footer-brand {
  hyphens: manual;
}

@media (max-width: 30rem) {
  h1,
  h2 {
    hyphens: auto;
  }
}

h2 {
  font-size: clamp(1.4rem, 3.5vw, 2rem);
  margin: 2.5rem 0 1rem;
}

/* The first heading of a band sets its own top edge through the band's padding. */
section > .wrap > h2:first-child,
.area-aside > h2:first-child,
.contact-aside > h2:first-child {
  margin-top: 0;
}

/* A quiet label above a page title: what kind of page this is. */
.eyebrow {
  margin: 0 0 0.5rem;
  color: var(--muted);
  font-size: 0.875rem;
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

h3 {
  font-size: 1.2rem;
  margin: 1.5rem 0 0.5rem;
}

a {
  color: var(--accent);
  text-underline-offset: 0.15em;
}

a:hover {
  text-decoration-thickness: 2px;
}

:focus-visible {
  outline: 3px solid var(--accent);
  outline-offset: 2px;
}

.skip-link {
  position: absolute;
  left: -999rem;
  top: 0;
  z-index: 10;
  padding: 0.5rem 1rem;
  background: var(--ink);
  color: var(--paper);
}

.skip-link:focus {
  left: 0;
}

/* Header */
.site-header {
  background: var(--paper);
  border-bottom: 1px solid var(--ground);
}

main {
  /* So a jump from the skip link or an anchor clears the sticky header. */
  scroll-margin-top: 6rem;
}

.header-inner {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.75rem 2rem;
  padding-top: 1rem;
  padding-bottom: 1rem;
}

.brand {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  margin-right: auto;
  color: var(--ink);
  text-decoration: none;
}

.brand-text {
  display: flex;
  flex-direction: column;
}

/* The crest beside the name: the file is 128 px tall, shown at half for a sharp
   mark on a high-density screen. It never shrinks when the header is tight. */
.brand-logo {
  height: 3.5rem;
  width: auto;
  flex-shrink: 0;
}

.brand-name,
.footer-brand {
  font-family: var(--font-serif);
  font-weight: 600;
  font-size: 1.25rem;
}

.brand-tagline {
  font-size: 0.875rem;
  color: var(--muted);
}

.site-nav ul {
  display: flex;
  flex-wrap: wrap;
  gap: 0.25rem 1.25rem;
  margin: 0;
  padding: 0;
  list-style: none;
}

.site-nav a {
  font-size: 1rem;
  color: var(--ink);
  text-decoration: none;
}

.site-nav a:hover,
.site-nav a[aria-current="page"] {
  color: var(--accent);
  text-decoration: underline;
}

.header-phone {
  display: none;
  margin-left: auto;
  font-weight: 600;
  white-space: nowrap;
  text-decoration: none;
}

/* Bands: one rhythm, so the page has a pulse instead of a drift */
section {
  padding: var(--band) 0;
}

.hero,
.band {
  background: var(--ground);
}

.hero-small {
  padding: calc(var(--band) * 0.7) 0;
}

.lead {
  max-width: var(--measure);
  font-size: 1.25rem;
  color: var(--ink);
}

/* Photographs. Each one is cropped by the box it sits in rather than by the
   file, so one file serves every screen; brand.css says where each picture is
   looked at (object-position), because that is a fact about the picture. */
/* <picture> only chooses the file; the <img> inside is what the layout places.
   ⚠ `display: contents` hands BOTH children to the grid, and <source> is not
   hidden by default: it took the first cell and pushed every photograph one
   cell along (the hero photo fell below the text, the teaser text into the
   photo's column; seen on the draft, 2026-09-21). The source still chooses the
   file when hidden: that happens in the document, not in the layout. */
picture {
  display: contents;
}

picture > source {
  display: none;
}

.photo {
  display: block;
  width: 100%;
  height: auto;
  object-fit: cover;
  background: var(--ground);
}

.photo-hero,
.photo-profile {
  border-top: 3px solid var(--accent);
}

.photo-teaser {
  border-radius: 50%;
  aspect-ratio: 1;
  max-width: 14rem;
}

.photo-office {
  margin-bottom: 1.5rem;
}

/* A hero in two parts: what the practice is, and who it is */
.hero-split > .wrap {
  display: grid;
  gap: 2rem;
}

/* The home hero: text on limestone, with the gable motif drawn beside it. The
   motif is decoration, so it is a background and never reaches the text layer.
   On a phone it drops below the text as a low band, where it cannot crowd the
   first screen (DESIGN_DIRECTION 4.5, section 1). */
.hero-home {
  position: relative;
  overflow: hidden;
  padding-bottom: calc(var(--band) + 5rem);
}

.hero-home > .wrap {
  position: relative;
  z-index: 1;
}

.hero-home::after {
  content: "";
  position: absolute;
  right: 0;
  bottom: 0;
  left: 0;
  height: 5.5rem;
  background: url("gable.svg") left bottom / auto 100% repeat-x;
  pointer-events: none;
}

.hero-home .actions {
  margin-top: 2rem;
}

.note {
  color: var(--muted);
  font-size: 1rem;
}

/* Buttons: the primary action filled, the secondary outlined */
.actions {
  display: flex;
  flex-wrap: wrap;
  gap: 0.75rem;
}

.button {
  display: inline-block;
  padding: 0.75rem 1.5rem;
  border: 2px solid var(--accent);
  border-radius: 999px;
  background: var(--accent);
  color: var(--paper);
  font-weight: 600;
  text-decoration: none;
}

.button:hover {
  text-decoration: underline;
}

.button-secondary {
  background: transparent;
  color: var(--accent);
}

/* Facts: four short claims, each under its own accent rule */
.facts {
  padding: 0;
}

.fact-list {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 1.75rem 1.5rem;
  /* ⚠ `margin: 0` here would undo the centring .wrap sets on the same element,
     which left the whole row against the window's edge while every other band
     stayed centred (seen on the draft, 2026-09-20). */
  margin: 0 auto;
  padding-top: var(--band);
  padding-bottom: var(--band);
  list-style: none;
}

.fact-list li {
  padding-top: 0.75rem;
  border-top: 3px solid var(--accent);
  font-size: 1rem;
  line-height: 1.45;
}

.cards {
  display: grid;
  gap: 1.5rem;
  margin: 0;
  padding: 0;
  list-style: none;
}

.card {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
  padding: 1.5rem;
  border-top: 3px solid var(--accent);
  background: var(--paper);
}

.card h3 {
  margin: 0;
  font-size: 1.3rem;
}

.card h3 a {
  text-decoration: none;
}

.card h3 a:hover {
  text-decoration: underline;
}

.card p {
  margin: 0;
  color: var(--muted);
}

/* The Häufige Anlässe: each one a way straight into its section */
.card-links {
  margin: 0.25rem 0 0;
  padding: 0;
  list-style: none;
  font-size: 1rem;
}

.card-links li {
  padding: 0.45rem 0;
  border-top: 1px solid var(--ground);
}

.card-links a {
  color: var(--ink);
  text-decoration: none;
}

.card-links a:hover {
  color: var(--accent);
  text-decoration: underline;
}

/* A section reached by its link clears the sticky header. */
h2[id],
h3[id] {
  scroll-margin-top: 6rem;
}

/* Häufige Fragen: native disclosure, no script */
.faq details {
  border-top: 1px solid var(--ground);
}

.faq details:last-child {
  border-bottom: 1px solid var(--ground);
}

.faq summary {
  display: flex;
  justify-content: space-between;
  gap: 1rem;
  padding: 1rem 0;
  font-weight: 600;
  cursor: pointer;
  list-style: none;
}

.faq summary::-webkit-details-marker {
  display: none;
}

.faq summary::after {
  content: "+";
  flex-shrink: 0;
  font-family: var(--font-serif);
  font-size: 1.4rem;
  line-height: 1;
  color: var(--accent);
}

.faq details[open] summary::after {
  content: "\2212";
}

.faq details p {
  margin: 0 0 1.25rem;
  max-width: var(--measure);
}

/* "So läuft ein Mandat": the number is the mark, in the serif, in Sandstein */
.steps {
  display: grid;
  gap: 1.75rem;
  margin: 0 0 2.5rem;
  padding-left: 0;
  list-style: none;
  counter-reset: step;
}

.steps > li {
  display: grid;
  grid-template-columns: 2.5rem 1fr;
  gap: 0 1rem;
  counter-increment: step;
  max-width: calc(var(--measure) + 3.5rem);
}

.steps > li::before {
  content: counter(step);
  grid-row: span 2;
  font-family: var(--font-serif);
  font-size: 2.25rem;
  font-weight: 600;
  line-height: 1;
  color: var(--accent);
}

.steps h3 {
  margin: 0 0 0.25rem;
}

.steps p {
  margin: 0;
  max-width: var(--measure);
}

.checklist {
  padding-left: 1.25rem;
  max-width: var(--measure);
}

.checklist li {
  margin-bottom: 0.35rem;
}

.more::after {
  content: " \2192";
}

address {
  font-style: normal;
}

/* A Rechtsgebiet: the text in one column, what the page covers beside it.
   The aside follows the reader down on a wide screen, so the way to ask a
   question is never a scroll away (DESIGN_DIRECTION 4.3, dash & lion). */
.area-grid,
.profile-grid,
.contact-grid {
  display: grid;
  gap: 2.5rem;
}

.area-aside,
.profile-aside,
.contact-aside {
  padding: 1.5rem;
  background: var(--ground);
  font-size: 1rem;
}

.area-aside ul,
.profile-aside ul,
.contact-aside ul {
  margin: 0 0 1.25rem;
  padding-left: 1.25rem;
}

.area-aside li,
.profile-aside li,
.contact-aside li {
  margin-bottom: 0.35rem;
}

.area-aside h2,
.profile-aside h2,
.contact-aside h2 {
  font-size: 1.15rem;
  margin: 1.75rem 0 0.75rem;
}

.area-aside .button,
.contact-aside .button {
  width: 100%;
  text-align: center;
}

/* The profile: a life read as a line, each station on the accent */
.timeline {
  margin: 0 0 1.5rem;
  padding-left: 0;
  list-style: none;
  max-width: var(--measure);
}

.timeline li {
  position: relative;
  padding: 0 0 1rem 1.5rem;
  border-left: 2px solid var(--paper);
}

.timeline li::before {
  content: "";
  position: absolute;
  top: 0.55em;
  left: -0.4rem;
  width: 0.65rem;
  height: 0.65rem;
  border-radius: 50%;
  background: var(--accent);
}

/* A sentence of the practice's own voice, set in the serif */
.pull-quote {
  margin: 2rem 0;
  padding-left: 1.25rem;
  border-left: 3px solid var(--accent);
  font-family: var(--font-serif);
  font-size: 1.3rem;
  line-height: 1.4;
  max-width: var(--measure);
}

/* Footer */
.site-footer {
  padding: 2.5rem 0 6rem;
  background: var(--ink);
  color: var(--paper);
  font-size: 1rem;
}

.site-footer a,
.site-footer h2 {
  color: var(--paper);
}

.site-footer h2 {
  margin: 0 0 0.5rem;
  font-size: 1rem;
}

.footer-grid {
  display: grid;
  gap: 2rem;
}

.footer-grid section {
  padding-bottom: 0;
}

.footer-grid ul {
  margin: 0;
  padding: 0;
  list-style: none;
}

.footer-brand {
  margin: 0;
}

/* On a phone the two ways to reach the Kanzlei stay in reach (DESIGN_DIRECTION 4.2) */
.action-bar {
  position: fixed;
  right: 0;
  bottom: 0;
  left: 0;
  display: flex;
  gap: 0.5rem;
  padding: 0.5rem;
  border-top: 1px solid var(--ground);
  background: var(--paper);
}

.action-bar .button {
  flex: 1;
  padding: 0.6rem 0.5rem;
  text-align: center;
}

@media (min-width: 48rem) {
  .site-header {
    position: sticky;
    top: 0;
    z-index: 20;
  }

  /* The name on the left; the phone number above the navigation on the right,
     instead of wrapping onto a row of its own. */
  .header-inner {
    display: grid;
    grid-template-columns: auto minmax(0, 1fr);
    grid-template-areas:
      "brand phone"
      "brand nav";
    align-items: center;
    gap: 0.35rem 2rem;
  }

  .brand {
    grid-area: brand;
    margin-right: 0;
  }

  .site-nav {
    grid-area: nav;
    justify-self: end;
  }

  .site-nav ul {
    justify-content: flex-end;
  }

  .header-phone {
    grid-area: phone;
    justify-self: end;
    margin-left: 0;
  }

  .fact-list {
    grid-template-columns: repeat(4, 1fr);
  }

  .cards {
    grid-template-columns: repeat(auto-fit, minmax(16rem, 1fr));
  }


  .footer-grid {
    grid-template-columns: 2fr 1fr 1fr 1fr;
  }

  .site-footer {
    padding-bottom: 2.5rem;
  }

  .header-phone {
    display: inline;
  }

  .action-bar {
    display: none;
  }
}

/* A photograph answers the empty right side better than a drawing, so where
   there is one the motif stands down. Every Kanzlei before its shoot, and the
   synthetic one in the gate, keeps the drawing. */
.hero-home:has(.photo-hero)::after {
  display: none;
}

.hero-home:has(.photo-hero) {
  padding-bottom: var(--band);
}

/* The profile teaser: a round portrait beside the sentence it belongs to */
.teaser-grid {
  display: grid;
  gap: 1.5rem;
  align-items: start;
}

@media (min-width: 48rem) {
  .teaser-grid {
    grid-template-columns: 14rem minmax(0, 1fr);
    gap: 2.5rem;
  }
}

/* Wide enough that the motif can stand beside the text instead of under it. */
@media (min-width: 64rem) {
  .hero-home {
    padding-bottom: var(--band);
  }

  .hero-split > .wrap {
    grid-template-columns: minmax(0, 1fr) 26rem;
    align-items: center;
    gap: 3rem;
  }

  .hero-text {
    max-width: 40rem;
  }

  /* Beside a photograph the title's column is narrower (528px at 1024px wide),
     so the title scales with the window: 2.4rem there holds the 12.9em word in
     about 490px, and it grows to 3rem as the column does. */
  .hero-split h1 {
    font-size: clamp(2.4rem, 3.4vw, 3rem);
  }

  .photo-hero {
    aspect-ratio: 4 / 5;
  }

  .photo-profile {
    aspect-ratio: 3 / 4;
    max-width: 22rem;
    justify-self: end;
  }

  .hero-home::after {
    top: 0;
    left: auto;
    width: min(40%, 26rem);
    height: auto;
    background: url("gable.svg") right bottom / contain no-repeat;
  }

}

@media (min-width: 60rem) {
  .area-grid {
    grid-template-columns: minmax(0, 1fr) 20rem;
    gap: 3.5rem;
  }

  /* Placed rather than ordered: the aside is first in the document for the sake
     of the heading order, and belongs on the right for the sake of the reader. */
  .area-main {
    grid-column: 1;
    grid-row: 1;
  }

  .area-aside {
    grid-column: 2;
    grid-row: 1;
  }

  .profile-grid,
  .contact-grid {
    grid-template-columns: minmax(0, 1fr) 21rem;
    gap: 3.5rem;
  }

  .area-aside,
  .profile-aside,
  .contact-aside {
    position: sticky;
    top: 7rem;
    align-self: start;
  }
}

@media (prefers-reduced-motion: reduce) {
  * {
    transition: none !important;
    animation: none !important;
  }
}

/* The enquiry form. No script anywhere: the browser validates what it can, and
   the function checks everything again (ADR-0004). */
.enquiry {
  max-width: var(--measure);
}

.contact-list {
  margin: 0 0 1.25rem;
  padding-left: 0;
  list-style: none;
}

.field {
  display: grid;
  gap: 0.25rem;
  margin: 0 0 1rem;
}

.field label {
  font-size: 1rem;
  font-weight: 600;
}

.enquiry input,
.enquiry select,
.enquiry textarea {
  width: 100%;
  padding: 0.7rem 0.75rem;
  border: 1px solid var(--muted);
  border-radius: 4px;
  background: var(--paper);
  color: var(--ink);
  font: inherit;
}

.enquiry input:focus,
.enquiry select:focus,
.enquiry textarea:focus {
  border-color: var(--accent);
}

/* What a visitor must read before typing their matter: set apart, not buried. */
.enquiry .hint {
  padding-left: 0.75rem;
  border-left: 3px solid var(--accent);
}

.hint {
  margin: -0.5rem 0 1rem;
  color: var(--muted);
  font-size: 1rem;
}

/* The honeypot: off-screen rather than hidden, so a bot fills it and a person
   never sees it. Never display:none, which some bots check for. */
.hp {
  position: absolute;
  left: -999rem;
}
