/* ============================================================
   Selbstwerk Kiosk — design system

   Light, white-dominant, #0E5D8A as the structural accent.

   Everything is sized in viewport-height units so the same layout holds on
   any 16:9 panel, 1080p or 4K, without a media query. --u is the base unit:
   1vh = 10.8px at 1080p.

   Legibility floor: this is read from several metres away, not from a desk.
   Body copy stays at or above ~2.4vh (≈26px at 1080p); only secondary labels
   go smaller.
   ============================================================ */

@font-face {
  font-family: 'Encode Sans';
  src: url('/static/fonts/EncodeSans.woff2') format('woff2');
  font-weight: 100 900;
  font-display: swap;
}
@font-face {
  font-family: 'Inter';
  src: url('/static/fonts/Inter.woff2') format('woff2');
  font-weight: 100 900;
  font-display: swap;
}

:root {
  --u: 1vh;

  /* Brand — #0E5D8A is confirmed from the logo and the website. */
  --blue: #0E5D8A;
  --blue-deep: #002735;
  --blue-soft: #ABD1FD;
  --tint: #E3EFF7;
  --tint-weak: #F4F9FC;
  --canvas: #FFFFFF;
  --ink: #002735;
  --muted: #5C7180;
  --line: #D3E3ED;

  /* Status colours are functional rather than brand: reading open-vs-closed
     correctly from across the hall outranks palette purity. */
  --open: #177A47;
  --closed: #B3261E;
  --limited: #B26A00;

  /* Workshop areas */
  --area-holz: #A9662E;
  --area-metall: #55697A;
  --area-keramik: #B4553F;
  --area-textil: #8A4F7D;
  --area-druck: #2E7D6B;
  --area-fahrrad: #B07C15;
  --area-haus: #0E5D8A;

  --fs-hero: 8.4vh;
  --fs-h1: 5vh;
  --fs-h2: 3.6vh;
  --fs-lg: 3vh;
  --fs-md: 2.5vh;
  --fs-sm: 2.1vh;
  --fs-xs: 1.7vh;

  --gap: 2.2vh;
  --radius: 1.2vh;
}

* { box-sizing: border-box; }

html, body {
  margin: 0;
  padding: 0;
  height: 100%;
  overflow: hidden;
  background: var(--canvas);
  color: var(--ink);
  font-family: 'Inter', system-ui, -apple-system, 'Segoe UI', sans-serif;
  font-size: var(--fs-md);
  -webkit-font-smoothing: antialiased;
}

h1, h2, h3, .display {
  font-family: 'Encode Sans', 'Inter', sans-serif;
  font-weight: 700;
  letter-spacing: -0.01em;
  margin: 0;
}

/* ---------- Stage ------------------------------------------------------ */

.stage {
  display: grid;
  grid-template-rows: auto 1fr auto;
  height: 100vh;
  width: 100vw;
}

/* ---------- Header ----------------------------------------------------- */

.header {
  display: flex;
  align-items: center;
  gap: calc(var(--gap) * 1.2);
  padding: 1.8vh 3vh;
  border-bottom: 0.35vh solid var(--line);
  background: var(--canvas);
}

.header__mark {
  height: 9vh;
  width: auto;
  display: block;
  border-radius: 0.6vh;
}

.header__titles { flex: 1; min-width: 0; }

.header__title {
  font-size: var(--fs-h1);
  color: var(--blue);
  line-height: 1.05;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.header__clock { text-align: right; line-height: 1; }

.header__time {
  font-family: 'Encode Sans', sans-serif;
  font-weight: 700;
  font-size: 6.4vh;
  color: var(--blue-deep);
  font-variant-numeric: tabular-nums;
  letter-spacing: -0.02em;
}

.header__date {
  font-size: var(--fs-sm);
  color: var(--muted);
  margin-top: 0.5vh;
  font-weight: 500;
  white-space: nowrap;
}

/* ---------- Screens ---------------------------------------------------- */

.main { position: relative; overflow: hidden; }

.screen {
  position: absolute;
  inset: 0;
  /* The bottom padding reserves a clear band for the rotation dots and the
     page counter, which are positioned over this area. Without it the content
     runs straight into them. */
  padding: 2.6vh 3vh 7vh;
  display: flex;
  flex-direction: column;
  gap: var(--gap);
  opacity: 0;
  visibility: hidden;
  transform: translateY(1.2vh);
  transition: opacity .55s ease, transform .55s ease, visibility .55s;
}

.screen.is-active {
  opacity: 1;
  visibility: visible;
  transform: none;
}

.section__label {
  font-family: 'Encode Sans', sans-serif;
  font-weight: 700;
  font-size: var(--fs-sm);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--muted);
  margin-bottom: 1.2vh;
  display: flex;
  align-items: center;
  gap: 1.2vh;
}

.section__label::after {
  content: '';
  flex: 1;
  height: 0.25vh;
  background: var(--line);
}

/* ---------- Heute ------------------------------------------------------ */

/* A block that should absorb leftover vertical space. The Heute screen often
   has only two or three things on it, and a wall of white below them reads as
   broken rather than calm. */
.block { display: flex; flex-direction: column; min-height: 0; }
.block--grow { flex: 1; }

.open-grid {
  flex: 1;
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(30vh, 1fr));
  gap: var(--gap);
  align-content: stretch;
  min-height: 0;
}

.open-card {
  background: var(--tint-weak);
  border: 0.3vh solid var(--line);
  border-left: 1.1vh solid var(--area, var(--blue));
  border-radius: var(--radius);
  padding: 2.6vh 2.8vh;
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: 1.2vh;
  min-width: 0;
  max-height: 34vh;
}

.open-card__area {
  font-family: 'Encode Sans', sans-serif;
  font-weight: 700;
  font-size: 5.6vh;
  color: var(--area, var(--blue));
  line-height: 1.05;
  overflow-wrap: anywhere;
}

.open-card__until {
  font-size: var(--fs-h2);
  color: var(--ink);
  font-weight: 600;
}

/* "Demnächst" — what to come back for. */
.soon-grid {
  flex: 1;
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(28vh, 1fr));
  gap: 1.4vh;
  align-content: start;
  min-height: 0;
}

.soon {
  background: #fff;
  border: 0.25vh solid var(--line);
  border-top: 0.7vh solid var(--area, var(--blue));
  border-radius: var(--radius);
  padding: 1.6vh 1.8vh;
  display: flex;
  flex-direction: column;
  gap: 0.6vh;
  min-width: 0;
  max-height: 22vh;
}

.soon__day {
  font-size: var(--fs-sm);
  font-weight: 700;
  color: var(--area, var(--blue));
  text-transform: uppercase;
  letter-spacing: 0.05em;
}

.soon__title {
  font-size: var(--fs-md);
  font-weight: 600;
  line-height: 1.2;
  overflow: hidden;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow-wrap: anywhere;
}

.soon__time { font-size: var(--fs-sm); color: var(--muted); margin-top: auto; }

.badge {
  display: inline-flex;
  align-items: center;
  gap: 0.7vh;
  align-self: flex-start;
  font-size: var(--fs-xs);
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  padding: 0.5vh 1.1vh;
  border-radius: 10vh;
  color: #fff;
  background: var(--open);
}

.badge--dot::before {
  content: '';
  width: 1vh;
  height: 1vh;
  border-radius: 50%;
  background: currentColor;
}

.badge--closed { background: var(--closed); }
.badge--limited { background: var(--limited); }
.badge--soldout { background: var(--muted); }

.entry-list {
  display: flex;
  flex-direction: column;
  gap: 1.1vh;
  min-height: 0;
  overflow: hidden;
}

.entry {
  display: grid;
  grid-template-columns: 15vh 1fr auto;
  align-items: center;
  gap: 2vh;
  padding: 1.4vh 1.8vh;
  border-radius: var(--radius);
  background: var(--tint-weak);
  border-left: 0.8vh solid var(--area, var(--blue));
}

.entry__time {
  font-weight: 700;
  font-size: var(--fs-lg);
  color: var(--blue-deep);
  font-variant-numeric: tabular-nums;
}

.entry__title {
  font-size: var(--fs-md);
  font-weight: 600;
  line-height: 1.2;
  min-width: 0;
  overflow: hidden;
  overflow-wrap: anywhere;
}

/* Course titles carry a pipe separating the workshop from the course name
   ("Keramikwerkstatt | Vase mit Durchblick"). Each part gets its own line —
   far easier to read than one long run. */
.title-line { display: block; }

/* The part before the pipe names the workshop, so it reads as a kicker above
   the course name rather than as part of it. */
.course__title .title-line:first-child:not(:only-child) {
  font-size: var(--fs-md);
  color: var(--area, var(--blue));
  opacity: 0.85;
}

.entry__meta {
  font-size: var(--fs-sm);
  color: var(--muted);
  white-space: nowrap;
}

/* Closures are deliberately styled as an aside, never as programme items.
   The wall must not advertise "Heute geschlossen: Fahrradwerkstatt" as though
   it were something to come along to. */
.closures {
  display: flex;
  flex-wrap: wrap;
  gap: 1.2vh;
  padding-top: 0.4vh;
}

.closure {
  display: flex;
  align-items: center;
  gap: 1vh;
  padding: 1vh 1.6vh;
  border-radius: var(--radius);
  background: #FBEDEC;
  border: 0.25vh solid #F2CFCC;
  color: #7A1A15;
  font-size: var(--fs-sm);
  font-weight: 600;
}

.closure--limited {
  background: #FDF3E3;
  border-color: #F0DCBB;
  color: #7A4A05;
}

.closure__area { font-weight: 700; }

/* Whole-building closure takes over the screen — it is the only thing worth
   saying that day. */
.house-closed {
  flex: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  text-align: center;
  gap: 2vh;
}

.house-closed__title {
  font-size: var(--fs-hero);
  color: var(--closed);
  line-height: 1;
}

.house-closed__note {
  font-size: var(--fs-h2);
  color: var(--muted);
  font-weight: 500;
  max-width: 70%;
}

.empty-state {
  flex: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  text-align: center;
  gap: 1.6vh;
  color: var(--muted);
}

.empty-state__title { font-size: var(--fs-h1); color: var(--blue); }
.empty-state__note { font-size: var(--fs-lg); }

/* ---------- Diese Woche ------------------------------------------------ */

.week {
  flex: 1;
  display: grid;
  grid-template-columns: repeat(7, 1fr);
  gap: 1.2vh;
  min-height: 0;
}

.day {
  display: flex;
  flex-direction: column;
  border-radius: var(--radius);
  background: var(--tint-weak);
  border: 0.25vh solid var(--line);
  overflow: hidden;
  min-width: 0;
}

.day.is-today {
  border-color: var(--blue);
  border-width: 0.45vh;
  background: #fff;
  box-shadow: 0 0.8vh 2.4vh rgba(14, 93, 138, 0.14);
}

.day.is-closed { background: #FBEDEC; border-color: #F2CFCC; }

.day__head {
  padding: 1.2vh 1.2vh 0.9vh;
  text-align: center;
  border-bottom: 0.25vh solid var(--line);
  background: var(--canvas);
}

.day.is-today .day__head { background: var(--blue); }
.day.is-today .day__name,
.day.is-today .day__date { color: #fff; }

.day__name {
  font-family: 'Encode Sans', sans-serif;
  font-weight: 700;
  font-size: var(--fs-md);
  color: var(--blue-deep);
  text-transform: uppercase;
  letter-spacing: 0.04em;
}

.day__date { font-size: var(--fs-xs); color: var(--muted); margin-top: 0.2vh; }

.day__body {
  flex: 1;
  padding: 1.2vh;
  display: flex;
  flex-direction: column;
  gap: 1.2vh;
  overflow: hidden;
}

/* Days here typically hold one to three evening slots. Chips are sized to
   fill the column rather than huddle at the top of it — a sparse week is the
   normal case, so it has to look deliberate. */
.chip {
  position: relative;
  border-radius: 0.9vh;
  padding: 1.4vh 1.2vh;
  background: #fff;
  border-left: 0.7vh solid var(--area, var(--blue));
  border-top: 0.2vh solid var(--line);
  border-right: 0.2vh solid var(--line);
  border-bottom: 0.2vh solid var(--line);
  min-width: 0;
  overflow: hidden;
}

.chip__content {
  display: flex;
  flex-direction: column;
  gap: 0.4vh;
  min-width: 0;
}

/* The workshop name leads: it is what a visitor scans the column for. The
   time is the qualifier, so it sits underneath. */
.chip__title {
  font-size: var(--fs-md);
  font-weight: 700;
  line-height: 1.15;
  color: var(--area, var(--blue));
  overflow: hidden;
  display: -webkit-box;
  -webkit-line-clamp: 3;
  -webkit-box-orient: vertical;
  /* German compounds like "Keramikwerkstatt" are wider than a day column, so
     they must be allowed to break rather than spill out of the chip. */
  overflow-wrap: anywhere;
  hyphens: auto;
}

.chip__time {
  font-size: var(--fs-sm);
  font-weight: 600;
  color: var(--muted);
  font-variant-numeric: tabular-nums;
  line-height: 1.1;
}


/* A closed slot keeps its normal shape and still names the workshop and the
   time it would have run — but faded, with a banner struck across it, so it
   reads as cancelled at a glance instead of as programme. */
.chip--closed {
  background: #FAFCFD;
  border-left-color: #C3CED4;
  /* Extra room below the text so the banner has a band of its own to cross,
     rather than sitting on top of the workshop name — which is the one thing
     the chip still has to communicate. */
  padding-bottom: 4.4vh;
}

.chip--closed .chip__content { opacity: 0.45; }
.chip--closed .chip__title { color: var(--ink); }

.chip__banner {
  position: absolute;
  left: 50%;
  bottom: 1vh;
  transform: translateX(-50%) rotate(-9deg);
  background: var(--closed);
  color: #fff;
  font-family: 'Encode Sans', sans-serif;
  font-size: 1.5vh;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  padding: 0.4vh 1.4vh;
  white-space: nowrap;
  border-radius: 0.3vh;
  box-shadow: 0 0.3vh 1vh rgba(0, 39, 53, 0.2);
  pointer-events: none;
}

.chip--more {
  font-size: var(--fs-xs);
  color: var(--muted);
  text-align: center;
  font-weight: 600;
  border: none;
  background: none;
  padding-top: 0.2vh;
}

.day__empty {
  flex: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  text-align: center;
  color: #A9BCC7;
  font-size: var(--fs-sm);
  font-weight: 500;
  padding: 0 1vh;
}

/* ---------- Workshops -------------------------------------------------- */

.workshops {
  flex: 1;
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: var(--gap);
  min-height: 0;
}

/* Pages of three courses; one is shown at a time and the page advances each
   time the workshops screen comes round in the rotation. */
.workshops-page { display: none; }
.workshops-page.is-active { display: grid; }

.page-count {
  position: absolute;
  bottom: 2.2vh;
  right: 3vh;
  font-size: var(--fs-xs);
  color: var(--muted);
  font-weight: 600;
}

.course {
  display: flex;
  flex-direction: column;
  border-radius: var(--radius);
  overflow: hidden;
  background: #fff;
  border: 0.25vh solid var(--line);
  box-shadow: 0 0.6vh 2vh rgba(0, 39, 53, 0.07);
  min-width: 0;
}

.course__image {
  height: 30vh;
  background: var(--tint) center/cover no-repeat;
  flex-shrink: 0;
}

.course__body {
  flex: 1;
  padding: 1.8vh;
  display: flex;
  flex-direction: column;
  gap: 1vh;
  min-height: 0;
}

.course__date {
  font-size: var(--fs-sm);
  font-weight: 700;
  color: var(--area, var(--blue));
  text-transform: uppercase;
  letter-spacing: 0.05em;
}

.course__title {
  font-family: 'Encode Sans', sans-serif;
  font-weight: 700;
  font-size: var(--fs-lg);
  line-height: 1.15;
  color: var(--blue-deep);
  overflow: hidden;
  display: -webkit-box;
  -webkit-line-clamp: 3;
  -webkit-box-orient: vertical;
}

.course__foot {
  margin-top: auto;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1.2vh;
  padding-top: 1vh;
  border-top: 0.25vh solid var(--line);
}

.course__price {
  font-size: var(--fs-h2);
  font-weight: 700;
  font-family: 'Encode Sans', sans-serif;
  color: var(--blue);
}

.course__qr {
  width: 9vh;
  height: 9vh;
  display: block;
  border-radius: 0.6vh;
}

.course__cta { font-size: var(--fs-xs); color: var(--muted); text-align: right; }

/* ---------- Status rail ------------------------------------------------ */

.rail {
  display: flex;
  align-items: center;
  gap: 2.4vh;
  padding: 0 3vh;
  height: 10vh;
  background: var(--tint);
  border-top: 0.35vh solid var(--line);
  overflow: hidden;
  transition: height .3s ease;
}

/* With no solar readout and no ticker the rail carries only the URL, so it
   gives most of its height back to the content above. */
.rail--slim { height: 5.5vh; }

.solar {
  display: flex;
  align-items: center;
  gap: 1.4vh;
  flex-shrink: 0;
}

.solar__icon { width: 4.4vh; height: 4.4vh; flex-shrink: 0; }

.solar__figures { display: flex; align-items: baseline; gap: 1.6vh; }

.solar__power {
  font-family: 'Encode Sans', sans-serif;
  font-weight: 700;
  font-size: 4.6vh;
  color: var(--blue);
  font-variant-numeric: tabular-nums;
  line-height: 1;
}

.solar__unit { font-size: var(--fs-md); color: var(--muted); font-weight: 600; }

/* Today's yield is always shown next to current power. Without it the rail
   reads "0 kW" every evening and looks broken rather than dark. */
.solar__today { font-size: var(--fs-sm); color: var(--muted); font-weight: 500; }
.solar__today strong { color: var(--blue-deep); font-weight: 700; }

.solar--offline .solar__power { color: var(--muted); }

.rail__spacer { flex: 1; }

.rail__brand {
  font-size: var(--fs-sm);
  color: var(--muted);
  font-weight: 600;
  white-space: nowrap;
}

/* Ticker takes the rail over when a message is live. */
.ticker {
  flex: 1;
  display: flex;
  align-items: center;
  gap: 1.6vh;
  min-width: 0;
  overflow: hidden;
}

.ticker__label {
  flex-shrink: 0;
  background: var(--blue);
  color: #fff;
  font-family: 'Encode Sans', sans-serif;
  font-weight: 700;
  font-size: var(--fs-sm);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  padding: 0.7vh 1.4vh;
  border-radius: 0.7vh;
}

.ticker__viewport { flex: 1; overflow: hidden; min-width: 0; }

.ticker__track {
  display: inline-flex;
  white-space: nowrap;
  will-change: transform;
  animation: ticker-scroll var(--ticker-duration, 26s) linear infinite;
}

.ticker__item {
  font-size: var(--fs-lg);
  font-weight: 600;
  color: var(--blue-deep);
  /* Separates one repeat from the next so the text does not run together. */
  padding-right: 8vh;
}

/* A message that already fits is shown still, and the duplicate is dropped.
   Scrolling it would mean the rail sits empty for most of the cycle — the
   opposite of what an urgent notice is for. */
.ticker__track--static { animation: none; }
.ticker__track--static .ticker__item + .ticker__item { display: none; }
.ticker__track--static .ticker__item { padding-right: 0; }

/* The track holds exactly two copies, so travelling 50% of its width lands
   the second copy precisely where the first began: a continuous loop with no
   blank stretch. */
@keyframes ticker-scroll {
  from { transform: translateX(0); }
  to   { transform: translateX(-50%); }
}

/* ---------- Splash ----------------------------------------------------- */

.splash {
  position: fixed;
  inset: 0;
  z-index: 100;
  background: var(--blue);
  color: #fff;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 3vh;
  padding: 8vh;
  text-align: center;
  animation: splash-in .4s ease;
}

@keyframes splash-in {
  from { opacity: 0; transform: scale(1.02); }
  to   { opacity: 1; transform: none; }
}

.splash__label {
  font-family: 'Encode Sans', sans-serif;
  font-weight: 700;
  font-size: var(--fs-h2);
  letter-spacing: 0.22em;
  text-transform: uppercase;
  opacity: 0.75;
}

.splash__text {
  font-family: 'Encode Sans', sans-serif;
  font-weight: 700;
  font-size: 9vh;
  line-height: 1.1;
  max-width: 90%;
}

.splash__mark { position: absolute; bottom: 5vh; height: 7vh; opacity: 0.9; }

/* ---------- Rotation indicator ----------------------------------------- */

.dots {
  position: absolute;
  bottom: 2.4vh;
  left: 50%;
  transform: translateX(-50%);
  display: flex;
  gap: 0.9vh;
  z-index: 5;
}

.dot {
  position: relative;
  width: 1vh;
  height: 1vh;
  border-radius: 1vh;
  background: var(--line);
  overflow: hidden;
  transition: width .35s ease, background .35s ease;
}

/* The active dot doubles as the dwell timer: it stretches into a track and
   fills left-to-right, so the wall shows how long until the next screen. */
.dot.is-active {
  width: 4vh;
  background: #C4DBE8;
}

.dot__fill {
  position: absolute;
  inset: 0;
  background: var(--blue);
  transform: scaleX(0);
  transform-origin: left center;
}

.dot.is-active .dot__fill {
  animation: dot-fill var(--dwell, 20s) linear forwards;
}

/* Pinned to one screen, or a splash is up: nothing is counting down, so show
   the dot solid rather than a bar that fills and then lies about advancing. */
.dots.is-paused .dot.is-active .dot__fill {
  animation: none;
  transform: scaleX(1);
}

@keyframes dot-fill {
  from { transform: scaleX(0); }
  to   { transform: scaleX(1); }
}

/* ---------- Connection warning ----------------------------------------- */

/* Deliberately discreet: a data problem should be visible to staff without
   shouting at visitors. */
.offline-note {
  position: fixed;
  top: 1.2vh;
  right: 1.2vh;
  z-index: 200;
  background: var(--limited);
  color: #fff;
  font-size: var(--fs-xs);
  font-weight: 700;
  padding: 0.5vh 1.2vh;
  border-radius: 0.6vh;
  opacity: 0;
  transition: opacity .4s;
  pointer-events: none;
}

body.is-offline .offline-note { opacity: 0.92; }

/* Area colour assignment */
.area-holz    { --area: var(--area-holz); }
.area-metall  { --area: var(--area-metall); }
.area-keramik { --area: var(--area-keramik); }
.area-textil  { --area: var(--area-textil); }
.area-druck   { --area: var(--area-druck); }
.area-fahrrad { --area: var(--area-fahrrad); }
.area-haus    { --area: var(--area-haus); }
