:root {
  /* Jerusalem stone palette — muted, dusty, aged */
  --stone-bg: #e8e0cf;
  --stone-light: #d6cdb8;
  --stone-mid: #c4b89f;
  --stone-shadow: #a99b80;
  --stone-deep: #82725a;
  --ochre: #786545;
  --walnut: #3a2f26;
  --walnut-dark: #241b14;
  --ink: #1f1610;
  --brass: #9c7f4a;

  /* Jerusalem stone slab texture — shared across every flap face so each
     cell looks cut from the same piece. Each cell randomises its
     background-position via --bg-x / --bg-y for natural variation.
     Source: 1024×1024 seamless meleke photo (CC0, ChatGPT-generated). */
  --stone-texture: url("stone.jpg?v=448ef317bb78aae44ae325228604e97efee58ee7");
  --stone-tile: 360px 360px;

  /* Cells flex to fill the frame so the whole board always fits the
     viewport with no horizontal scroll. Hard cap is 13 cells across
     (MAX_COLS in app.js); rows are padded so every row has the same
     count, keeping cell width uniform. Per-cell sizing (width / height
     / font-size) is derived from the cell's own size via container
     queries — no --cell-w / --cell-h vars needed. */
  --cell-gap: 0px;
}

* { box-sizing: border-box; }

html, body {
  margin: 0;
  padding: 0;
  background:
    radial-gradient(circle at 30% 20%, rgba(255,255,255,0.18) 0%, transparent 45%),
    radial-gradient(circle at 70% 70%, rgba(120,101,69,0.08) 0%, transparent 55%),
    var(--stone-bg);
  background-attachment: fixed;
  color: var(--ink);
  font-family: 'Frank Ruhl Libre', 'Times New Roman', serif;
  min-height: 100vh;
}

main {
  /* Caps the board on wide screens; cells flex-fill within. */
  max-width: 1500px;
  margin: 0 auto;
  padding: 1rem;
}

/* ─── Display housing ────────────────────────────────────────── */
.display-frame {
  background: linear-gradient(180deg, var(--walnut) 0%, var(--walnut-dark) 100%);
  border: 4px solid var(--ochre);
  border-radius: 14px;
  padding: clamp(0.75rem, 2vw, 1.5rem);
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,0.05),
    inset 0 -2px 8px rgba(0,0,0,0.45),
    0 8px 22px rgba(36, 27, 20, 0.3),
    0 2px 4px rgba(0,0,0,0.2);
  overflow: hidden;
  margin-bottom: 1.5rem;
  /* Sized container so the smaller header flaps below can be expressed
     as a fraction of the frame's content width via cqw. */
  container-type: inline-size;
}

/* Brass-plate header: two stacked rows of smaller flap cells than the
   body so they read as a subordinate row above the message. The top
   row carries the Hebrew date alone (cells flush to the visual right
   per RTL); the bottom row carries the day-of-week on the visual right
   and the wall-clock time on the visual left, separated by at least
   one cell-sized empty gap (just brass plate showing through, no real
   tile in it) — matching the per-cell `min(56px, 5cqw)` expression so
   the gap and cells shrink together as the viewport narrows. */
.board-header {
  display: flex;
  flex-direction: column;
  align-items: stretch;
  gap: var(--cell-gap);
  margin-bottom: 6px;
  min-width: 0;
}

/* Bottom row reads as one continuous strip of HEADER_COLS flaps —
   sections are siblings with the same cell-gap as cells inside each
   section, so the dow + spacer + time tiles look uniform across the
   row. Width: 100% combined with `flex: <cells> 1 0` on each child
   section makes them share the row width in proportion to their cell
   count. */
.board-header .header-bottom-row {
  display: flex;
  align-items: stretch;
  gap: var(--cell-gap);
  width: 100%;
  min-width: 0;
}

.board-header .header-section {
  display: flex;
  gap: var(--cell-gap);
  min-width: 0;
  /* Default: section flex-fills its parent. The bottom row has three
     sections (dow / spacer / time) sharing the row width — JS sets
     each one's inline `flex-grow` to its cell count, so the row
     reads as 16 uniformly-sized tiles total just like the top row. */
  flex: 1 1 0;
}

/* Time digits read left-to-right even though the rest of the frame is
   RTL — without this override "14:30" comes out as "03:41". */
.board-header .header-time {
  direction: ltr;
}

/* Header cells flex-fill the row (no fixed-width override), so 18
   tiles span the frame width with the same gaps as a body row. Body
   rows have 13 flex-filling cells, so body cells are slightly wider
   than header cells — that subordination is exactly the visual
   hierarchy we want, no extra rules needed. */
.board-header .cell {
  /* falls through to `.cell { flex: 1 1 0; … }` */
}

/* Cells in the notile section between dow and time. Same width and
   height as a real flap cell (so the row stays uniform), but with no
   visual content — the brass plate of .display-frame shows through. */
.board-header .header-notile-cell {
  flex: 1 1 0;
  min-width: 0;
  aspect-ratio: 3 / 4;
}

/* Footer for the Sefirat HaOmer count — mirrors the header's "smaller
   subordinate row" treatment but stacks two flex rows below the
   message body. Both lines are padded in JS to the same FOOTER_COLS
   so the cells are uniformly sized; flex: 1 1 0 on each cell shares
   the row width equally. With ~30 cells per line, each is roughly
   half the width of a body cell. */
.board-footer {
  display: flex;
  flex-direction: column;
  gap: var(--cell-gap);
  margin-top: 6px;
  min-width: 0;
}

.board-footer .footer-line {
  display: flex;
  gap: var(--cell-gap);
  width: 100%;
  /* dir="rtl" is inherited from .board */
}

.board {
  display: flex;
  flex-direction: column;
  gap: var(--cell-gap);
  width: 100%;
}

.board-row {
  display: flex;
  /* dir="rtl" on the board already lays children right-to-left;
     a row-reverse here would double-reverse and read LTR. */
  gap: var(--cell-gap);
  width: 100%;
}

/* ─── Flap cell ──────────────────────────────────────────────── */
.cell {
  position: relative;
  flex: 1 1 0;
  min-width: 0;
  aspect-ratio: 3 / 4;
  /* Establish a containment context so descendants can size with cqw/cqi. */
  container-type: inline-size;
  background: var(--walnut-dark);
  /* Force the cell to its own stacking context so the .letter overlay
     reliably paints above the half-seam shadows regardless of which
     descendants the browser composites on separate layers. */
  isolation: isolate;
}

.cell .half {
  position: absolute;
  left: 0;
  right: 0;
  height: 50%;
  overflow: hidden;
  display: flex;
  align-items: center;
  justify-content: center;
  /* Explicit z-index keeps the halves below the .letter overlay even on
     browsers that composite descendants onto separate layers. */
  z-index: 0;
  /* 93cqi ≈ 0.7 × cell-height (cell aspect 3:4, height = 4/3 × width). */
  font-size: 93cqi;
  line-height: 1;
  font-weight: 700;
  color: var(--ink);
  background-image:
    linear-gradient(180deg, rgba(255,247,228,0.72) 0%, rgba(220,205,178,0.50) 100%),
    var(--stone-texture);
  background-size: auto, var(--stone-tile);
  background-position: 0 0, var(--bg-x, 0%) var(--bg-y, 0%);
  background-repeat: no-repeat, repeat;
  user-select: none;
  /* Chiselled-groove shadow: deeper dark above + brighter highlight below
     read more clearly against the lighter stone face. */
  text-shadow:
    0 -1px 1px rgba(0, 0, 0, 0.75),
    0  1px 1px rgba(255, 250, 235, 0.90),
    0  0   2px rgba(0, 0, 0, 0.20);
}

.cell .half.top {
  top: 0;
  background-image:
    linear-gradient(180deg, rgba(255,247,228,0.80) 0%, rgba(220,205,178,0.55) 75%, rgba(220,205,178,0.92) 100%),
    var(--stone-texture);
  align-items: flex-end;
  /* No seam in the static state — the line was reading as cutting
     through the letter even with the .letter overlay z-indexed above
     it (anti-aliased glyph edges let a 0.05–0.15 alpha line bleed
     through the centre of the character). The .flap element keeps
     its own border-bottom so the seam still reads during the flip
     animation. */
}

.cell .half.top span {
  transform: translateY(50%);
}

.cell .half.bottom {
  bottom: 0;
  background-image:
    linear-gradient(180deg, rgba(220,205,178,0.92) 0%, rgba(220,205,178,0.55) 25%, rgba(180,160,130,0.45) 100%),
    var(--stone-texture);
  /* Deterministic offset from the top so the bottom half shows a *different*
     slice of the slab (otherwise both halves mirror identical pixels). */
  background-position:
    0 0,
    calc(var(--bg-x, 0%) + 37%) calc(var(--bg-y, 0%) + 53%);
  align-items: flex-start;
  /* No inset shadow on the top edge — see the comment on .half.top. */
}

.cell .half.bottom span {
  transform: translateY(-50%);
}

/* The flipping flap (covers the top half during animation) */
.cell .flap {
  position: absolute;
  left: 0;
  right: 0;
  top: 0;
  height: 50%;
  background-image:
    linear-gradient(180deg, rgba(255,247,228,0.80) 0%, rgba(220,205,178,0.55) 75%, rgba(220,205,178,0.92) 100%),
    var(--stone-texture);
  background-size: auto, var(--stone-tile);
  background-position: 0 0, var(--bg-x, 0%) var(--bg-y, 0%);
  background-repeat: no-repeat, repeat;
  border-bottom: 1px solid rgba(0,0,0,0.05);
  display: flex;
  align-items: flex-end;
  justify-content: center;
  /* 93cqi ≈ 0.7 × cell-height (cell aspect 3:4, height = 4/3 × width). */
  font-size: 93cqi;
  line-height: 1;
  font-weight: 700;
  color: var(--ink);
  text-shadow:
    0 -1px 1px rgba(0, 0, 0, 0.75),
    0  1px 1px rgba(255, 250, 235, 0.90),
    0  0   2px rgba(0, 0, 0, 0.20);
  overflow: hidden;
  transform-origin: 50% 100%;
  z-index: 2;
}

.cell .flap span {
  transform: translateY(50%);
  user-select: none;
}

.cell.flipping .flap {
  animation: fold-down 80ms ease-in forwards;
}

/* Whole-letter overlay drawn above the seam between the two halves, so
   the static letter reads as a single character rather than two clipped
   halves with a visible groove through the middle. Hidden during a flip
   (opacity: 0 below) so the standard split-flap animation still reads.
   Critically, this sits *above* the .flap (z-index 2) — the flap covers
   the top half at rest and carries its own border-bottom at y=50%, so
   without raising .letter above it the seam line painted in front of
   the glyph. During a flip the letter is invisible, so its higher
   z-index doesn't interfere with the fold. */
.cell .letter {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 93cqi;
  line-height: 1;
  font-weight: 700;
  color: var(--ink);
  pointer-events: none;
  user-select: none;
  z-index: 3;
  text-shadow:
    0 -1px 1px rgba(0, 0, 0, 0.75),
    0  1px 1px rgba(255, 250, 235, 0.90),
    0  0   2px rgba(0, 0, 0, 0.20);
}

.cell.flipping .letter {
  opacity: 0;
}

@keyframes fold-down {
  0%   { transform: scaleY(1); }
  100% { transform: scaleY(0); }
}

/* ─── Controls ───────────────────────────────────────────────── */
.controls {
  background: rgba(255, 255, 255, 0.45);
  border: 1px solid var(--stone-shadow);
  border-radius: 12px;
  padding: 1rem 1.25rem;
  box-shadow: 0 2px 6px rgba(61, 43, 31, 0.15);
  backdrop-filter: blur(2px);
}

.controls label {
  font-weight: 700;
  color: var(--walnut);
  font-size: 1.05rem;
}

.controls input[type="date"],
.controls select {
  font-family: 'Frank Ruhl Libre', serif;
  font-size: 1.05rem;
  padding: 0.45rem 0.8rem;
  border: 1px solid var(--stone-deep);
  border-radius: 8px;
  background: var(--stone-bg);
  color: var(--ink);
  cursor: pointer;
}

.controls input[type="date"]:focus,
.controls select:focus {
  outline: 2px solid var(--brass);
  outline-offset: 1px;
}

.control-row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 1rem;
  margin-top: 0.9rem;
}

.controls button {
  font-family: 'Frank Ruhl Libre', serif;
  font-weight: 700;
  font-size: 1.05rem;
  padding: 0.55rem 1.4rem;
  background: linear-gradient(180deg, var(--brass) 0%, var(--ochre) 100%);
  color: var(--walnut-dark);
  border: 1px solid var(--ochre);
  border-radius: 8px;
  cursor: pointer;
  box-shadow: 0 2px 4px rgba(61,43,31,0.25), inset 0 1px 0 rgba(255,255,255,0.4);
  transition: transform 0.08s ease;
}

.controls button:hover { filter: brightness(1.05); }
.controls button:active { transform: translateY(1px); }

/* ─── Hebrew calendar popup ─────────────────────────────────── */
.hcal-wrap {
  position: relative;
  display: inline-block;
}

#hcal-toggle {
  font-size: 1.2rem;
  padding: 0.35rem 0.6rem;
  background: var(--stone-bg);
  border: 1px solid var(--stone-deep);
  border-radius: 8px;
  cursor: pointer;
  line-height: 1;
}

#hcal-toggle:hover { filter: brightness(1.04); }
#hcal-toggle:focus { outline: 2px solid var(--brass); outline-offset: 1px; }

.hcal-popup {
  position: absolute;
  top: calc(100% + 0.4rem);
  right: 0;
  z-index: 100;
  background: var(--stone-bg);
  border: 1px solid var(--stone-deep);
  border-radius: 10px;
  box-shadow: 0 6px 18px rgba(36, 27, 20, 0.25);
  padding: 0.6rem;
  min-width: 18rem;
  direction: rtl;
}

.hcal-popup[hidden] { display: none; }

.hcal-nav {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 0.5rem;
}

.hcal-nav button {
  font-family: 'Frank Ruhl Libre', serif;
  background: transparent;
  border: 1px solid var(--stone-deep);
  border-radius: 6px;
  padding: 0.2rem 0.55rem;
  cursor: pointer;
  color: var(--walnut);
}

.hcal-nav button:hover { background: var(--stone-light); }

.hcal-label {
  font-weight: 700;
  color: var(--walnut);
  font-size: 1.05rem;
}

.hcal-grid {
  display: grid;
  grid-template-columns: repeat(7, 1fr);
  gap: 3px;
}

.hcal-dow {
  text-align: center;
  font-weight: 700;
  color: var(--ochre);
  font-size: 0.85rem;
  padding: 0.25rem 0;
}

.hcal-day,
.hcal-pad {
  aspect-ratio: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  font-family: 'Frank Ruhl Libre', serif;
  font-size: 1rem;
  font-weight: 500;
  border-radius: 6px;
}

.hcal-pad { background: transparent; }

.hcal-day {
  background: rgba(255, 255, 255, 0.5);
  border: 1px solid transparent;
  color: var(--ink);
  cursor: pointer;
  padding: 0;
}

.hcal-day:hover {
  background: var(--stone-light);
  border-color: var(--stone-deep);
}

.hcal-day.selected {
  background: var(--ochre);
  color: var(--stone-bg);
  border-color: var(--walnut);
}

.page-footer {
  text-align: center;
  padding: 1.5rem 1rem 2.5rem;
  color: var(--ochre);
  opacity: 0.8;
}

.page-footer #build-sha a {
  color: inherit;
  text-decoration: none;
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
}

.page-footer #build-sha a:hover { text-decoration: underline; }

