/* Styles of this site, linked while this file exists.
   The layout module brings the structure; everything here is z'3280's own look.
   Colors come from identity as --color and --color-bg — the rest is mixed from those two. */

@import url('https://fonts.googleapis.com/css2?family=Caveat:wght@400;600&family=Jost:wght@300;400;500&family=Londrina+Sketch&family=Londrina+Solid&display=swap');

html {
  --width: 68rem; /* measure of header, content and footer */

  /* Two display faces, both Londrina, as the client asked for: Solid carries the
     headings, Sketch the oversized type where the rough outline still reads. Neither
     is a text face — the running text stays Jost, the handwriting Caveat. */
  --font-1: 'Jost', system-ui, sans-serif; /* u2 reads this one */
  --font-head: 'Londrina Solid', system-ui, sans-serif;
  --font-hand: 'Caveat', cursive;
  --font-logo: 'Londrina Solid', system-ui, sans-serif;
  --font-sketch: 'Londrina Sketch', 'Londrina Solid', system-ui, sans-serif;

  --radius: .25rem;

  font-weight: 300;
  line-height: 1.65;
  color-scheme: light;
}

/* Base typography, deliberately at zero specificity: a content module that wants a
   different heading — the oversized page title, say — must be able to say so without
   fighting an id selector. */
:where(h1, h2, h3, h4) {
  font-family: var(--font-head);
  font-weight: 400; /* Londrina Solid has no semibold; a synthesised one turns fat */
  text-transform: uppercase;
  letter-spacing: .04em;
  line-height: 1.15;
  margin: 0 0 .6em;
}

:where(h1) { font-size: clamp(1.5rem, 3vw, 2.1rem) }
:where(h2) { font-size: clamp(1.25rem, 2.2vw, 1.6rem) }
:where(h3) { font-size: 1.1rem }
x:where(p) { margin: 0 0 1.1em }

/* the site is monochrome: a link is marked by weight and rule, never by hue */
:where(a) { color: inherit }

#container {
  font-family: var(--font-1);

  #head {
    xbackground: color-mix(in srgb, var(--color-bg), white 50%);
    background: var(--color-bg);

    nav a {
      font-size: .92rem;
    }

    /* the call to action: whatever link the editor puts in that slot becomes the button
       (look under "Buttons" below) — in the bar it is a size smaller */
    [qcms-name=action] {
      p { margin: 0 }
      a { padding: .8em 1.5em }
    }
  }

  #foot {
    font-size: .92rem;
    background: color-mix(in srgb, var(--color-bg), black 2%);

    h2, h3 {
      font-size: .8rem;
      letter-spacing: .14em;
      margin-bottom: 1.1em;
    }
  }
}

/* Rule under a heading, as in the design. */
.rule::after {
  content: '';
  display: block;
  width: 4.5rem;
  height: 2px;
  background: var(--color);
  margin-top: .55em;
}

/* The hero opens with the wordmark — the module sizes it, the face is ours.
   At this size the sketched outline of Londrina Sketch is legible and carries the
   drawn hand of the whole site; small type gets Solid instead. */
[qcms-mod="cont.luca.pagehead"] .title {
  font-family: var(--font-sketch);
  font-weight: 400;
}

/* The sketched arrow beside the handwritten note: it comes down from the buttons
   above and its head runs into the first word, the way the drawing has it. */
[qcms-mod="cont.luca.hero"] .note {
  display: flex;
  align-items: flex-start;
  gap: .15rem;
}
[qcms-mod="cont.luca.hero"] .note::before {
  content: '';
  flex: none;
  width: 1.5rem;
  height: 1.6rem;
  margin-left: 1rem;
  margin-top: -.5rem;
  background: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 32 34' fill='none' stroke='%231a1714' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M5 2C3 14 6 25 21 29'/%3E%3Cpath d='M21 29 13 28M21 29 17 21'/%3E%3C/svg%3E") no-repeat center / contain;
}

/* The statements of the Coming-Soon deck. The module stays face-agnostic, as all the
   luca modules do — the voice is set here. Mixed case, not the versals the headings
   wear, because the deck is set that way. */
[qcms-mod="cont.luca.slide"] .line {
  font-family: var(--font-head);
  font-weight: 400;
  letter-spacing: .01em;
}

/* The one link on the deck. Same button as everywhere, but it must not inherit the
   huge type of the statement above it. 13px floor: the fluid root font would put
   .8rem near 10px on a phone. */
#container [qcms-mod="cont.luca.slide"] [qcms-name=actions] a {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  font-family: var(--font-1);
  font-weight: 400;
  font-size: max(.8rem, 13px);
  line-height: 1.2;
  padding-block: .8em;
}

[qcms-mod="cont.luca.hero"] {
  .lead { font-family: var(--font-sketch); font-weight: 400 }
  .sub { font-family: var(--font-head); font-weight: 400 }
}

/* A navigation standing in the content — the overview of a section, listing its pages.
   The module brings the list and nothing else: measure, arrangement and voice are the
   site's, the same drawn frame the buttons elsewhere wear. */
#container #content [qcms-mod="cont.nav3"] {
  width: min(100% - 2rem, var(--width));
  margin: clamp(2rem, 5vw, 4rem) auto clamp(3rem, 7vw, 6rem);

  ul {
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    gap: .8rem;
    list-style: none;
    margin: 0;
    padding: 0;
  }
}

/* cms-image2 is width:100% and takes its height from its aspect ratio — so the width has
   to come from the link around it, otherwise it collapses to its min-width. */
.head-logo { flex: none; width: 7rem }
#foot .foot-brand > a { display: block; width: 9rem; margin-bottom: .8rem }

/* Die Fussadresse kommt aus den identity-Einstellungen, direkt im Template. Sie hatte
   bis dahin ein eigenes Cont-Modul, dessen CSS diese zwei Zeilen waren. */
#foot .foot-address { font-style: normal; line-height: 1.7 }

/* The drawing is ink on white — multiply lets the paper show through it. */
#foot .foot-grid > :is(img, cms-image2) { mix-blend-mode: multiply }

/* The fourth column of the footer held a pen drawing of the old town. The competition
   uses those pictures, so this house does not — until there is a drawing of its own, the
   three remaining columns share the width instead of leaving a gap where it stood.

   `auto-fit` statt einer festen Spaltenzahl: die Spalten brechen um, sobald sie unter
   ihre Mindestbreite fielen — auf dem Telefon steht der Fuss dadurch untereinander,
   ohne dass hier ein Umbruchpunkt geraten werden muss. Das ist nicht Bequemlichkeit,
   sondern nötig: diese Regel ist spezifischer als die Media-Queries des Layout-Moduls
   (`#container #foot .foot-grid` plus `:not(:has(…))`) und würde sie sonst auch schmal
   überstimmen — dann stünden drei Spalten auf 390 px nebeneinander und der Text bräche
   mitten im Wort.

   `min(15rem, 100%)`: ohne das `min()` wäre die Mindestbreite auf einem sehr schmalen
   Gerät breiter als der Behälter, und das Raster liefe seitlich hinaus. */
#container #foot .foot-grid:not(:has(> :is(img, cms-image2))) {
  grid-template-columns: repeat(auto-fit, minmax(min(15rem, 100%), 1fr));
}

/* ---------- Hand-drawn strokes ----------
   The frames and rules of the design are drawn, not ruled. A displacement filter on a
   border-only layer gives that without touching the text it surrounds — the filter would
   otherwise blur and warp the letters. */

/* Buttons — the one place they are made. The rich-text filter drops classes, so a link
   becomes a button by the slot it stands in, not by a class (doc/README.md).
   Only where a button is actually meant — in a note or a feature the action is a plain
   text link, and a drawn frame around it would be wrong.

   `:where()` keeps the list at the weight of `#container a`: the few places that differ
   (bar, deck, the emphatic hero button) override it with an ordinary `#container …`.

   The frame is drawn on a pseudo-element, the element itself keeps only its fill. Its
   own border stays as a transparent pixel so the size does not change. */
#container :where(
  [qcms-name=action],
  :is([qcms-mod="cont.luca.hero"], [qcms-mod="cont.luca.notebar"], [qcms-mod="cont.luca.slide"]) [qcms-name=actions],
  #content [qcms-mod="cont.nav3"]
) a {
  position: relative;
  display: inline-block;
  font-size: .78rem;
  text-transform: uppercase;
  letter-spacing: .13em;
  text-decoration: none;
  padding: .95em 1.8em;
  border: 1px solid transparent;
  border-radius: var(--radius);
  transition: background .2s, color .2s;

  &:hover { background: var(--color); color: var(--color-bg) }

  &::before {
    content: '';
    position: absolute;
    inset: 0;
    border: 2px solid currentColor;
    border-radius: inherit;
    filter: url(#sketch);
    pointer-events: none;
  }
}

/* An emphatic button is a filled one — there the drawn frame would only muddy the edge. */
#container [qcms-mod="cont.luca.hero"] [qcms-name=actions] a:first-of-type {
  background: var(--color);
  color: var(--color-bg);

  &:hover { background: none; color: var(--color) }
  &::before { border-color: transparent }
}

/* Rules under headings, drawn with the same hand. */
#container .rule::after {
  filter: url(#sketch);
}

/* The current page in the navigation is underlined by hand as well.

   Das Layout-Modul gibt jedem Link einen echten `border-bottom: 2px solid transparent`
   und färbt ihn für Hover und die aktuelle Seite ein. Diese Site zeichnet ihren Strich
   stattdessen als `::after` mit dem Sketch-Filter — der Rahmen des Moduls muss also in
   *allen drei* Zuständen unsichtbar bleiben, sonst liegt eine gerade Linie unter der
   gezeichneten. Die beiden Zustandsregeln sind nötig, weil `#container #head nav a`
   allein (2,0,2) gegen das `.cmsActive > a` des Moduls (2,1,2) verliert; gleichauf
   gewinnt diese Datei, weil sie nach dem Modul geladen wird. */
#container #head nav a {
  position: relative;
  border-bottom-color: transparent;
}
#container #head nav a:hover,
#container #head nav .cmsActive > a {
  border-bottom-color: transparent;
}
#container #head nav :is(.cmsActive, .cmsInside) > a::after,
#container #head nav a:hover::after {
  content: '';
  position: absolute;
  left: 0;
  right: 0;
  bottom: -.15em;
  border-bottom: 2px solid currentColor;
  filter: url(#sketch);
}

/* ---------- The menu panel on a phone ----------
   The layout module gives the sheet and the row-sized targets; here it gets the
   voice of the site. */
@media (width < 48rem) {
  /* Reading distance on a phone is shorter and the thumb is coarser than a mouse —
     the bar type may be small, the panel type must not be. */
  #container #head nav a {
    font-size: max(1.15rem, 17px); /* the fluid root font would leave this at 15px */
    font-family: var(--font-head);
    font-weight: 500;
    text-transform: uppercase;
    letter-spacing: .06em;
  }

  /* The row is the tap target, so it runs the full width — and a rule under a full-width
     row would sit right on top of the separator below it and read as a double line.
     Every row is indented, so the labels stay in one column and the mark has its margin. */
  #container #head nav a { padding-left: 2.1rem }

  /* Zwei Unterschiede zur breiten Ansicht, beide nötig:

     Erstens markiert hier nur die Seite selbst. In der Leiste oben stehen Abschnitt und
     Seite nebeneinander, da ist es richtig, dass „Logbuch" mitleuchtet, wenn man auf
     „Feedback" ist. Untereinander gelesen sehen zwei markierte Zeilen dagegen aus wie
     zwei aktuelle Seiten.

     Zweitens ist ein Unterstrich in einer senkrechten Liste das falsche Zeichen: er
     liegt auf der Trennlinie zur nächsten Zeile. Stattdessen ein senkrechter Strich
     links neben der Beschriftung — in derselben gezeichneten Hand, der Filter bleibt. */
  #container #head nav .cmsInside:not(.cmsActive) > a::after { content: none }

  #container #head nav .cmsActive > a::after {
    left: .55rem;
    right: auto;
    top: 50%;
    bottom: auto;
    translate: 0 -50%;
    width: auto;
    height: 1.05em;
    border-bottom: 0;
    border-left: 2px solid currentColor;
  }

  /* There is no hover on a touch screen — only a stroke left behind after a tap. */
  #container #head nav a:hover::after { content: none }

  /* At 320 px the logo, the burger and the button are one row's worth of space with
     nothing to spare — the gap and the button's letter-spacing are where it comes from. */
  #container #head .head-bar {
    gap: .75rem;
    flex-wrap: nowrap;
  }
  #container #head .head-logo { width: 6rem }
  #container #head [qcms-name=action] a {
    padding: .7em 1em;
    letter-spacing: .08em;
    white-space: nowrap;
  }
}



/* ---------- The menu lies on a placemat ----------
   A lighter sheet under the dishes, with the same torn edge as the note cards. */
#container [qcms-mod="cont.luca.menu"] .mat {
  position: relative;
  isolation: isolate;
  padding: clamp(1.5rem, 4vw, 3rem);
}
#container [qcms-mod="cont.luca.menu"] .mat::before {
  content: '';
  position: absolute;
  inset: 0;
  z-index: -1;
  background: color-mix(in srgb, var(--color-bg), white 65%);
  /* drop-shadow follows the torn outline; box-shadow would trace the rectangle behind it */
  filter: url(#deckle) drop-shadow(2px 2px 4px #0003);
}


/* ---------- Blocks fade in as they come up ----------
   Pure CSS (scroll-driven animation): no JS state, so content is never left invisible
   because a script failed or is still loading. Without browser support the blocks are
   simply there. Applies to the blocks of a page, not to what sits inside them. */

@keyframes reveal {
  from { opacity: 0; translate: 0 1.5rem }
  to   { opacity: 1; translate: 0 0 }
}

@media (prefers-reduced-motion: no-preference) {
  @supports (animation-timeline: view()) {
    /* A run of statements is excluded: it is many screens tall, so there is no moment at
       which it "comes up" — and it brings its own arriving, one statement at a time. */
    #content > [qcms-name=main] > *:not([qcms-mod="cont.luca.slides"]) {
      animation: reveal linear both;
      animation-timeline: view();
      animation-range: entry 0% entry 55%;
    }
  }
}

/* ---------- Coming Soon: eine Aussage zur Zeit ----------
   Die Aussagen liegen jetzt in einem `<u2-carousel>` übereinander: die Seite ist einen
   Bildschirm hoch, es gibt nichts zu scrollen und nichts einzurasten. Die frühere Regel
   (`scroll-snap-type` am Wurzelelement, auf diese Seite begrenzt) ist damit weg.

   Ohne JavaScript bleibt das Element unbekannt und die Aussagen stehen untereinander —
   dann scrollt man, ohne Einrasten. Das ist der Rückfall und braucht keine eigene Regel. */


/* ---------- Die Sprachwahl im Kopf ----------
   Zwei Kürzel neben dem Reservieren-Knopf, in derselben Versalschrift wie er, nur
   leichter — sie soll auffindbar sein und nicht mitreden. Das Modul bringt die Liste
   und den Trennstrich mit; hier bekommt sie die Stimme der Site.

   Wichtig ist das Abgrenzen nach oben: die Regeln für `#head nav a` sind für die
   Menüleiste geschrieben (gezeichneter Unterstrich, auf dem Telefon grosse Zeilen im
   Klappmenü) und träfen sonst auch dieses `<nav>`. */
#container #head [qcms-mod="cont.lang.choose2"] {
  flex: none;
}
#container #head [qcms-mod="cont.lang.choose2"] a {
  font-family: var(--font-1);
  font-size: max(.75rem, 12px);
  font-weight: 400;
  line-height: 1;
  text-transform: uppercase;
  letter-spacing: .12em;
  text-decoration: none;
  padding: .5rem .1rem; /* Fingerbreite, ohne die Zeile höher zu machen */
  opacity: .55;
}
#container #head [qcms-mod="cont.lang.choose2"] a:hover { opacity: 1 }

/* Die aktuelle Sprache steht da, ist aber kein Ziel — sie wird nicht unterstrichen,
   sondern trägt einfach volles Gewicht. */
#container #head [qcms-mod="cont.lang.choose2"] a[aria-current] {
  opacity: 1;
  font-weight: 500;
}
#container #head [qcms-mod="cont.lang.choose2"] a::after,
#container #head [qcms-mod="cont.lang.choose2"] a:hover::after { content: none }

/* Drei Dinge, die das Modul anders löst, als diese Kopfzeile es braucht — darum hier
   überschrieben und nicht dort geändert:

   u2 gibt Flex-Listen einen Abstand; er lag zwischen Trennstrich und „FR" und riss die
   Kürzel auseinander (`gap: 0`, den Abstand macht der Strich selbst).

   Das Modul richtet mittig aus und schiebt den Strich mit `margin: auto` in die Mitte der
   Zeile. Hier soll er auf der Grundlinie der Kürzel sitzen — `align-items: baseline` auf
   beiden Ebenen, und das `auto` muss weg, sonst zentriert es weiter. Die Ausrichtung steht
   auch am `ul`, weil das Klappmenü dieser Site jedes `a` im Kopf zum Block macht. */
#container #head [qcms-mod="cont.lang.choose2"] ul {
  gap: 0;
  align-items: baseline;
}
#container #head [qcms-mod="cont.lang.choose2"] li { align-items: baseline }
#container #head [qcms-mod="cont.lang.choose2"] li::after {
  margin: 0 .2em;
  opacity: .3;
}

@media (width < 48rem) {
  /* Gegen die Regeln des Klappmenüs, die jedes `nav a` im Kopf gross und gesperrt
     setzen — hier bleibt es das kleine Kürzel. */
  #container #head [qcms-mod="cont.lang.choose2"] a {
    font-size: max(.75rem, 12px);
    font-family: var(--font-1);
    letter-spacing: .12em;
    padding: .5rem .1rem;
  }
}

/* Auf dem Telefon stapelt das Layout-Modul jede Liste im Kopf zu Zeilen — richtig für
   das Klappmenü, falsch hier: „DE | FR" fiel dabei auf zwei Zeilen auseinander. Diese
   eine Liste bleibt darum in jeder Breite eine Zeile. */
#container #head [qcms-mod="cont.lang.choose2"] ul {
  display: flex;
  flex-direction: row; /* das Klappmenü stellt Listen im Kopf senkrecht */
  flex-wrap: nowrap;
  white-space: nowrap;
}

/* ---------- Gästebuch ----------
   `cms.cont.form.entries` liefert je Eintrag eine Definitionsliste: zu jedem Feld seine
   Beschriftung und seinen Wert, in der Reihenfolge des Formulars. Das Modul weiss nichts
   von „Name" oder „Wort" — welches Feld hier wie spricht, entscheidet diese Datei.

   Für „Ihre Worte" heisst das: die Beschriftungen verschwinden (neben dem Wort steht das
   Wort), der Name trägt die Zeile, das Datum steht klein daneben. */
#container [qcms-mod="cont.form.entries"] {
  max-width:45rem;
  margin: 4rem auto;

  .-entry {
    margin-block: clamp(1.5rem, 4vw, 2.5rem);

    /* Zwei Spalten, aber nur die erste Zeile teilt sie sich: dort stehen Name und Datum
       nebeneinander. Alles Weitere — die Nachricht, ein Bild — nimmt beide Spalten, sonst
       bräche der Text schon dort um, wo das Datum anfängt.

       Das `display: contents` an der Liste ist der Kniff dazu: ohne es wäre die ganze `dl`
       *ein* Rasterfeld, und die Zeilen darin wüssten vom Raster nichts. */
    display: grid;
    grid-template-columns: 1fr auto;
    align-items: baseline;
    column-gap: .6em;
  }

  dl { display: contents }
  dt { display: none }        /* die Beschriftung sagt hier nichts, was der Wert nicht sagt */
  dd { margin: 0 }

  u2-time {
    grid-column: 2;
    grid-row: 1;
    font-size: .85rem;
    color: color-mix(in srgb, var(--color), var(--color-bg) 40%);
  }

  /* Der Name trägt die Zeile — nicht weil das Modul ihn dafür hält, sondern weil dieses
     Formular ihn zuerst fragt. */
  .-field-name {
    grid-column: 1;
    grid-row: 1;
    font-family: var(--font-head);
    font-weight: 500;
  }

  /* Jedes weitere Feld über die volle Breite, in der Reihenfolge, in der es kommt. */
  dl > div:not(.-field-name) { grid-column: 1 / -1 }

  img { margin-top: .4rem }

  /* Wartet auf Freigabe: nur im Bearbeitungsmodus überhaupt sichtbar. */
  .-pending { opacity: .55 }
  .-release {
    grid-column: 1 / -1;
    font-size: .8rem;
  }
}
