/* The wall. A fixed stage (1080 x 1920 portrait or 1920 x 1080 landscape, scaled to fit whatever is
   viewing) holding tiles placed on a grid by the household's layout (shared/layout.js). Colours are
   the scheme's custom properties (shared/palettes.js), set by wall.js. Target hardware includes a
   Raspberry Pi 3 and a Chromecast, so motion is limited to the photo crossfade, the tile slide and a
   slow fade when colours change. */
:root {
  --bg: #f7f1e8; --ink: #3a2f26; --mut: #8d8073;
  --t1: #e8d6bf; --t1i: #6b4a1e; --t2: #e6cfc6; --t2i: #6b3a30; --t3: #d9d4c6; --t3i: #3f3d30;
  --today: #3a2f26; --todayi: #fff; --other: #efe8dd; --otheri: #b4a99a; --cell: #fff; --celli: #3a2f26;
  --chip: #e8e8e8; --chip-ink: #3a2f26; --today-chip: #534a42; --today-chip-ink: #fff; --other-chip: #dad3c9; --other-chip-ink: #b4a99a;
  --tile-shadow: 0 2px 4px rgba(45,35,25,.06), 0 16px 36px rgba(45,35,25,.13);
  --cell-shadow: 0 1px 2px rgba(45,35,25,.05), 0 7px 16px rgba(45,35,25,.11);
  --r: 43px;
  --ease: cubic-bezier(.4, 0, .2, 1);
}
* { box-sizing: border-box; }
html, body { height: 100%; margin: 0; background: #000; }
html.kiosk, html.kiosk * { cursor: none !important; }
body { overflow: hidden; font-family: Inter, system-ui, -apple-system, "Segoe UI", Roboto, "Noto Sans", "DejaVu Sans", sans-serif; }
body.editing { background: #15120f; }

/* --shift-x/y is the pixel shift wall.js applies against LCD image retention: the whole stage wanders a screen
   pixel at a time within a few pixels of center, so edges never sit on the same pixels all day. */
#app {
  position: absolute; left: 50%; top: 50%; width: 1080px; height: 1920px; overflow: hidden;
  transform: translate(calc(-50% + var(--shift-x, 0px) + var(--pan-x, 0px)), calc(-50% + var(--shift-y, 0px) + var(--pan-y, 0px))) rotate(var(--turn, 0deg)) scale(var(--scale, 1));
  transform-origin: center;
  background: var(--bg); color: var(--ink);
  transition: background-color 1.2s ease, color 1.2s ease;
}
body.editing #app { left: calc(50% - 170px); }
@media (max-width: 760px) { body.editing #app { left: 50%; top: calc(50% - 150px); } }
#app.no-anim, #app.no-anim * { transition: none !important; }
.corners { position: absolute; inset: 0; border-radius: 67px; box-shadow: 0 0 0 140px #000; pointer-events: none; z-index: 50; }
#app.square-corners .corners { display: none; }

/* ---------- Tiles ---------- */
#tiles { position: absolute; inset: 0; }
.tile {
  position: absolute; border-radius: var(--r); box-shadow: var(--tile-shadow); overflow: hidden;
  --k: 1; padding: calc(26px * var(--k)) calc(30px * var(--k));
  /* No left/top/width/height here: wall.js moves tiles between arrangements with transform and opacity,
     which the GPU animates without laying the page out again on every frame. */
  transition: background-color 1.2s ease, color 1.2s ease, box-shadow 1.2s ease;
}
.tile.c1 { background: var(--t1); color: var(--t1i); }
.tile.c2 { background: var(--t2); color: var(--t2i); }
.tile.c3 { background: var(--t3); color: var(--t3i); }
.tile.plain { background: transparent; box-shadow: none; padding: 0; overflow: visible; }
/* A tile in the owner's own colour (layout editor) for the look on screen, with text that reads on it. */
.tile.own { background: var(--tbg); color: var(--tink); }
.tile.plain.own { box-shadow: var(--tile-shadow); }
.tile.gone { opacity: 0; pointer-events: none; }
/* Screens with a weak GPU (WEAK_SCREEN in wall.js: a Raspberry Pi, a Chromecast, TV browsers) keep each tile on
   its own GPU layer, so tiles moving between arrangements are only slid, never painted again. */
.weak-screen #tiles > .tile { will-change: transform, opacity; }
/* Tiles moving between arrangements pass under the photo, then the calendar, rather than over them. */
#tiles > .tile.t-photo { z-index: 3; }
#tiles > .tile.t-month { z-index: 2; }
.tile.ghost { pointer-events: none; }
.lbl { font-size: calc(18px * var(--k)); letter-spacing: .1em; text-transform: uppercase; opacity: .75; margin-bottom: calc(6px * var(--k)); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.none { opacity: .6; }

/* ---------- Photo ---------- */
.t-photo { padding: 0; background: var(--other); }
.photo { position: absolute; left: 0; top: 0; opacity: 0; transition: opacity 1.2s ease; will-change: opacity; }
.photo.show { opacity: 1; }
.photo canvas { display: block; }
.photo-date { position: absolute; right: 22px; bottom: 16px; z-index: 3; font-size: 19px; color: #fff; text-shadow: 0 1px 6px rgba(0,0,0,.7); }
.t-photo.narrow .photo-date, .t-photo.short .photo-date { right: 16px; bottom: 11px; font-size: 14px; }
.photo-date:empty { display: none; }
.photo-empty { position: absolute; inset: 0; display: flex; align-items: center; justify-content: center; text-align: center; padding: 40px; font-size: 26px; color: var(--otheri); }
.photo-empty:empty { display: none; }
.photo-ctl { position: absolute; inset: 0; z-index: 5; touch-action: none; cursor: grab; }
.photo-ctl:active { cursor: grabbing; }
#app.readonly .photo-ctl { cursor: default; }
.menu-item { opacity: 0; transition: opacity .25s; pointer-events: none; }
.t-photo:hover .menu-item, .t-photo.menu .menu-item { opacity: 1; }
.t-photo:hover .nav, .t-photo.menu .nav, .t-photo:hover .zoom-meter, .t-photo.menu .zoom-meter, .t-photo:hover .tool, .t-photo.menu .tool { pointer-events: auto; }
#app.readonly .menu-item, #app.no-photos .menu-item { display: none; }
.cross { position: absolute; left: 50%; top: 50%; width: 0; height: 0; }
.cross::before, .cross::after { content: ''; position: absolute; background: rgba(255,255,255,.9); box-shadow: 0 0 3px rgba(0,0,0,.8); }
.cross::before { left: -1px; top: -70px; width: 2px; height: 140px; }
.cross::after { top: -1px; left: -70px; height: 2px; width: 140px; }
.nav {
  position: absolute; top: 50%; width: 76px; height: 76px; margin-top: -38px; border: 0; border-radius: 50%;
  background: rgba(0,0,0,.45); color: #fff; font: 600 44px/76px Inter, system-ui, sans-serif; text-align: center; padding: 0 0 6px;
  box-shadow: 0 2px 10px rgba(0,0,0,.4); cursor: pointer;
}
.nav.prev { left: 22px; }
.nav.next { right: 92px; }
.nav:active { background: rgba(0,0,0,.7); }
.zoom-meter { position: absolute; right: 18px; top: 16%; bottom: 16%; width: 48px; display: flex; flex-direction: column; align-items: center; gap: 8px; }
.zoom-meter .track { position: relative; flex: 1; width: 8px; border-radius: 4px; background: rgba(255,255,255,.3); box-shadow: 0 0 0 1px rgba(0,0,0,.25); }
.zoom-meter .fill { position: absolute; left: 0; right: 0; bottom: 0; border-radius: 4px; background: rgba(255,255,255,.85); }
.zoom-meter .thumb { position: absolute; left: 50%; width: 26px; height: 26px; margin: -13px 0 0 -13px; border-radius: 50%; background: #fff; box-shadow: 0 2px 10px rgba(0,0,0,.5); }
.zoom-meter .label { font-size: 18px; color: #fff; text-shadow: 0 1px 6px rgba(0,0,0,.7); font-variant-numeric: tabular-nums; }
.live-msg {
  position: absolute; left: 50%; top: 24px; transform: translateX(-50%); padding: .4em 1em; border-radius: 999px;
  background: rgba(0,0,0,.55); color: #fff; font-size: 20px; opacity: 0; transition: opacity .25s; pointer-events: none; white-space: nowrap;
}
.live-msg.show { opacity: 1; }

/* ---------- Clock ---------- */
.t-clock .time { font-size: calc(80px * var(--k)); font-weight: 600; line-height: 1; letter-spacing: -.03em; font-variant-numeric: tabular-nums; white-space: nowrap; }
.t-clock .time .ampm { font-size: calc(26px * var(--k)); font-weight: 600; letter-spacing: 0; vertical-align: top; margin-left: 6px; }
.t-clock .weekday { margin-top: calc(10px * var(--k)); font-size: calc(26px * var(--k)); font-weight: 600; }
.t-clock .agenda, .t-today .agenda { list-style: none; margin: calc(10px * var(--k)) 0 0; padding: 0; font-size: calc(20px * var(--k)); line-height: 1.55; }
.t-clock .agenda li, .t-today .agenda li { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.t-clock .agenda li b, .t-today .agenda li b { font-weight: 600; margin-right: .35em; font-variant-numeric: tabular-nums; }

/* ---------- Weather now ---------- */
.t-weather { display: flex; flex-direction: column; justify-content: center; padding: calc(24px * var(--k)) calc(30px * var(--k)); }
.t-weather .now { display: flex; align-items: flex-start; justify-content: space-between; }
.t-weather .temp { font-size: calc(78px * var(--k)); font-weight: 600; line-height: 1; letter-spacing: -.02em; font-variant-numeric: tabular-nums; }
.t-weather .temp .unit { font-size: .45em; vertical-align: top; margin-left: 2px; }
.t-weather .cond { display: flex; flex-direction: column; align-items: center; margin: -6px -4px 0 0; }
.t-weather .icon { width: calc(64px * var(--k)); height: calc(64px * var(--k)); opacity: .9; }
.t-weather .icon svg { width: 100%; height: 100%; display: block; }
.t-weather .label { font-size: calc(19px * var(--k)); line-height: 1.2; white-space: nowrap; }
.t-weather .sub { margin-top: calc(8px * var(--k)); font-size: calc(22px * var(--k)); line-height: 1.3; white-space: nowrap; }
.t-weather .stats { margin: calc(20px * var(--k)) 0 0; font-size: calc(21px * var(--k)); line-height: 1.57; }
.t-weather .stats div { display: flex; justify-content: space-between; gap: 10px; font-variant-numeric: tabular-nums; }
.t-weather .stats dt { opacity: .75; }
.t-weather .stats dd { margin: 0; font-weight: 600; white-space: nowrap; }

/* ---------- Weekly forecast ---------- */
.t-forecast ol { list-style: none; margin: 0; padding: 0; }
.t-forecast li { display: grid; grid-template-columns: calc(64px * var(--k)) 1fr auto 2.4em; column-gap: .5em; align-items: center; font-size: calc(22px * var(--k)); line-height: 1.5; font-variant-numeric: tabular-nums; }
/* Each day's low beside (or under) its high; its chance of rain only where there is room for it. */
.t-forecast li .lo { opacity: .6; text-align: right; }
.t-forecast li .pp { display: none; }
.t-forecast li .d { opacity: .8; }
.t-forecast li svg { width: calc(26px * var(--k)); height: calc(26px * var(--k)); justify-self: center; opacity: .85; }
.t-forecast li b { font-weight: 600; }
.t-forecast li.none { display: block; font-size: calc(20px * var(--k)); }

/* ---------- Month ---------- */
.t-month { display: flex; flex-direction: column; gap: calc(14px * var(--k)); }
.t-month .head { display: flex; align-items: baseline; gap: calc(14px * var(--k)); line-height: 1; }
/* The month's name and the year open the lists that turn the calendar; they look like plain text. */
.t-month .head button { font: inherit; color: inherit; background: none; border: 0; padding: 0; margin: 0; cursor: pointer; line-height: 1; -webkit-tap-highlight-color: transparent; }
.t-month .head .name { font-size: calc(53px * var(--k)); font-weight: 700; letter-spacing: -.01em; }
.t-month .head .year { font-size: calc(29px * var(--k)); color: var(--mut); }
.t-month .head .name:focus-visible, .t-month .head .year:focus-visible { outline: 2px solid currentColor; outline-offset: 4px; border-radius: 6px; }
.t-month .status { margin-left: auto; font-size: calc(19px * var(--k)); color: var(--mut); white-space: nowrap; }
.t-month .status:empty { display: none; }
/* "Today": back to this month, beside the year while the calendar shows another. */
.t-month .head .back {
  align-self: center; padding: calc(8px * var(--k)) calc(18px * var(--k)); border-radius: 999px;
  font-size: calc(19px * var(--k)); font-weight: 600; background: var(--today); color: var(--todayi); box-shadow: var(--cell-shadow);
}
.t-month .head .back[hidden] { display: none; }
/* The calendar takes sideways drags (wall.js turns the month); no text selection while dragging. */
.t-month { touch-action: pinch-zoom; -webkit-user-select: none; user-select: none; }
.t-month .grid.in-next { animation: month-in-next .34s var(--ease); }
.t-month .grid.in-prev { animation: month-in-prev .34s var(--ease); }
@keyframes month-in-next { from { transform: translateX(12%); opacity: 0; } }
@keyframes month-in-prev { from { transform: translateX(-12%); opacity: 0; } }
/* The month and year lists: a card under the name or the year, over the grid. */
.tile.t-month.picking { z-index: 30; }
.mpick {
  position: absolute; z-index: 30; display: grid; gap: calc(6px * var(--k)); padding: calc(12px * var(--k));
  border-radius: 24px; background: var(--cell); color: var(--celli); box-shadow: 0 0 0 1px var(--chip), var(--tile-shadow);
  animation: mpick-in .16s var(--ease);
}
.mpick.month { grid-template-columns: repeat(3, auto); }
.mpick.year { grid-template-columns: auto; max-height: calc(100% - 20px); overflow-y: auto; }
.mpick button {
  font: inherit; font-size: calc(26px * var(--k)); font-weight: 600; font-variant-numeric: tabular-nums; color: inherit;
  min-width: calc(96px * var(--k)); padding: calc(12px * var(--k)) calc(18px * var(--k)); border: 0; border-radius: 16px;
  background: none; cursor: pointer; -webkit-tap-highlight-color: transparent;
}
.mpick button:hover, .mpick button:focus-visible { background: var(--chip); outline: none; }
.mpick button.now { box-shadow: inset 0 0 0 2px var(--today); }
.mpick button.on { background: var(--today); color: var(--todayi); }
@keyframes mpick-in { from { opacity: 0; transform: translateY(-6px); } }
.t-month .weekdays { display: grid; grid-template-columns: repeat(7, 1fr); gap: 12px; padding: 0 14px; font-size: calc(19px * var(--k)); letter-spacing: .08em; color: var(--mut); text-transform: uppercase; }
/* Refresh: a quiet glyph at the right end of the weekday row, in the room left of SAT's column. The
   glyph stays small; ::before widens the tap area to 44 screen pixels whatever the stage's scale. */
.t-month .weekrow { position: relative; }
.t-month .refresh {
  position: absolute; right: 10px; top: 50%; transform: translateY(-50%);
  width: calc(30px * var(--k)); height: calc(30px * var(--k)); padding: 0; border: 0; background: none;
  color: var(--mut); opacity: .55; cursor: pointer; transition: opacity .2s;
}
.t-month .refresh[hidden] { display: none; }
.t-month .refresh::before { content: ''; position: absolute; left: 50%; top: 50%; width: max(100%, calc(44px / var(--scale, 1))); height: max(100%, calc(44px / var(--scale, 1))); transform: translate(-50%, -50%); }
.t-month .refresh:hover, .t-month .refresh:focus-visible { opacity: 1; outline: none; }
.t-month .refresh svg { width: 100%; height: 100%; display: block; fill: none; stroke: currentColor; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; }
.t-month .refresh.spin svg { animation: wall-spin .8s linear infinite; }
@keyframes wall-spin { to { transform: rotate(360deg); } }
body.editing .t-month .refresh { display: none; }
/* The sync result: a small pill right above the sync icon, over the empty right end of the month's
   heading row, fading in and out. */
.t-month .synced {
  position: absolute; right: 0; bottom: calc(100% + 8px); z-index: 2; pointer-events: none; white-space: nowrap;
  padding: calc(6px * var(--k)) calc(14px * var(--k)); border-radius: 999px; font-size: calc(18px * var(--k)); font-weight: 600;
  background: var(--cell); color: var(--celli); box-shadow: var(--cell-shadow);
  opacity: 0; transform: translateY(4px); transition: opacity .25s, transform .25s;
}
.t-month .synced.show { opacity: 1; transform: none; }
.t-month .grid { flex: 1; min-height: 0; display: grid; grid-template-columns: repeat(7, 1fr); grid-auto-rows: minmax(0, 1fr); gap: 12px; }
.day {
  --px: calc(12px * var(--k)); --py: calc(7px * var(--k));
  position: relative; min-height: 0; overflow: hidden; padding: var(--py) var(--px) 0; border-radius: 24px; cursor: pointer;
  background: var(--cell); color: var(--celli); box-shadow: var(--cell-shadow); display: flex; flex-direction: column;
  transition: background-color 1.2s ease, color 1.2s ease, box-shadow 1.2s ease;
}
#app.readonly .day { cursor: default; }
.day.other { background: var(--other); color: var(--otheri); box-shadow: none; }
.day.today { background: var(--today); color: var(--todayi); }
.day .num { flex: none; font-size: calc(24px * var(--k)); font-weight: 700; line-height: 1.15; font-variant-numeric: tabular-nums; }
/* The family wall's month squares: a day with events gets a header band, a shade of its own colour
   (--chip), and its events are written plainly under it, each with a dot in its colour. Today's square
   is the scheme's opposite and keeps one solid colour. */
.day.has-events .num { margin: calc(-1 * var(--py)) calc(-1 * var(--px)) 0; padding: var(--py) var(--px) calc(5px * var(--k)); background: var(--chip); }
.day.other.has-events .num { background: var(--other-chip); }
.day.today.has-events .num { background: var(--today); }
/* Titles wrap, up to four lines; fitEvents() keeps the events that fit whole and adds "+N more". */
.day .events { flex: 1; min-height: 0; overflow: hidden; display: flex; flex-direction: column; gap: 2px; margin: calc(5px * var(--k)) calc(-1 * var(--px)) 0; }
.grid { --evs: 1; }
.grid[data-text="xs"] { --evs: .78; }
.grid[data-text="s"] { --evs: .89; }
.grid[data-text="l"] { --evs: 1.2; }
.ev {
  flex: none; font-size: calc(13px * var(--k) * var(--evs)); line-height: 1.2; padding: 1px var(--px) 2px; color: var(--celli);
  white-space: normal; overflow-wrap: break-word; overflow: hidden;
  display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 4;
}
.ev .lead { white-space: nowrap; }
.ev .t { font-weight: 600; font-variant-numeric: tabular-nums; }
.t-agenda .item i { display: inline-block; width: .6em; height: .6em; border-radius: 50%; margin-right: .35em; vertical-align: .02em; }
/* The dot hangs in the square's left margin, close to its edge, so every line of an event (a wrapped
   title too) starts at the same place, lined up with the date above. */
.ev { position: relative; padding-left: calc(var(--px) + 1px); }
.ev i { position: absolute; left: max(2px, calc(3px * var(--k))); top: calc(1px + .35em); width: .5em; height: .5em; border-radius: 50%; }
.ev.cont { opacity: .8; }
.day.today .ev, .day.today .more { color: var(--todayi); }
.day.other .ev, .day.other .more { color: var(--other-chip-ink); }
.more { flex: none; font-size: calc(13px * var(--k) * var(--evs)); line-height: 1.2; padding: 1px var(--px) 2px; color: var(--celli); opacity: .7; }

/* ---------- Coming up (agenda list) ---------- */
.t-agenda ol { list-style: none; margin: 0; padding: 0; font-size: calc(21px * var(--k)); line-height: 1.5; overflow: hidden; }
.t-agenda .dayhead { margin-top: calc(10px * var(--k)); font-weight: 700; opacity: .85; white-space: nowrap; }
.t-agenda .dayhead:first-child { margin-top: 0; }
.t-agenda .item { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.t-agenda .item b { font-weight: 600; margin-right: .35em; font-variant-numeric: tabular-nums; }

/* ---------- To-do, meals, countdown, note, QR ---------- */
.t-todo ul { list-style: none; margin: 0; padding: 0; font-size: calc(22px * var(--k)); line-height: 1.55; }
.t-todo li { display: flex; align-items: baseline; gap: .5em; cursor: pointer; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
#app.readonly .t-todo li { cursor: default; }
.t-todo li::before { content: ''; flex: none; width: .75em; height: .75em; border: 2px solid currentColor; border-radius: 6px; opacity: .7; transform: translateY(.05em); }
.t-todo li.done { opacity: .5; text-decoration: line-through; }
.t-todo li.done::before { background: currentColor; }
.t-meals ol { list-style: none; margin: 0; padding: 0; font-size: calc(21px * var(--k)); line-height: 1.6; }
.t-meals li { display: grid; grid-template-columns: calc(58px * var(--k)) 1fr; gap: .5em; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.t-meals li .d { opacity: .7; font-weight: 600; }
.t-meals li.today { font-weight: 700; }
.t-meals li.today .d { opacity: 1; }
.t-countdown { display: flex; flex-direction: column; justify-content: center; }
.t-countdown .big { font-size: calc(84px * var(--k)); font-weight: 700; line-height: 1; letter-spacing: -.03em; font-variant-numeric: tabular-nums; }
.t-countdown .big small { font-size: .32em; font-weight: 600; letter-spacing: 0; margin-left: .25em; }
.t-countdown .title { font-size: calc(24px * var(--k)); font-weight: 600; margin-top: calc(10px * var(--k)); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.t-countdown .when { font-size: calc(18px * var(--k)); opacity: .7; margin-top: 4px; }
.t-note { display: flex; align-items: center; justify-content: center; text-align: center; }
.t-note .text { font-size: calc(30px * var(--k)); font-weight: 600; line-height: 1.3; white-space: pre-wrap; overflow: hidden; }
.t-note .text.long { font-size: calc(22px * var(--k)); font-weight: 500; }
.t-qr { display: flex; flex-direction: column; align-items: center; justify-content: center; gap: calc(8px * var(--k)); padding: calc(18px * var(--k)); }
.t-qr .code { flex: 1 1 auto; min-height: 0; max-width: 100%; aspect-ratio: 1; }
.t-qr .code svg { display: block; width: 100%; height: 100%; }
.t-qr .label { flex: none; font-size: calc(16px * var(--k)); text-align: center; opacity: .8; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; max-width: 100%; }
.t-spacer { background: transparent !important; box-shadow: none !important; }
body.editing .t-spacer { outline: 2px dashed rgba(255,255,255,.35); outline-offset: -2px; }

/* ---------- Every size a tile may take (layout.js) ----------
   wall.js tags each tile with its size: .row is one cell tall (102px), .short two (216px), .narrow
   two cells wide or less, .roomy five or more, .wide at least twice as wide as tall. One-row tiles are
   always 102px tall, so their type is set in pixels; taller ones scale with --k. Small text never
   drops below a size readable across a room. */
.lbl { flex-shrink: 0; font-size: min(28px, max(15px, calc(18px * var(--k)))); }
.tile.row { display: flex; align-items: center; gap: 18px; padding: 0 28px; white-space: nowrap; }
.tile.row .lbl { margin: 0; flex: none; font-size: 17px; }
.tile.row ol, .tile.row ul { margin: 0; min-width: 0; }
.tile.row.narrow { padding: 0 20px; gap: 12px; }

/* Clock: one row is the time and the weekday (and the next event when roomy); two rows wide put
   today's events beside the time. */
.t-clock.row .time { font-size: 52px; }
.t-clock.row .time .ampm { font-size: 18px; }
.t-clock.row .weekday { margin: 0; font-size: 24px; opacity: .8; }
.t-clock.row.narrow .weekday { display: none; }
.t-clock.row .agenda { display: none; }
.t-clock.row.roomy .agenda { display: block; margin: 0 0 0 auto; min-width: 0; font-size: 22px; line-height: 1.3; text-align: right; }
.t-clock.row.roomy .agenda li:not(:first-child) { display: none; }
.t-clock:not(.row) { display: flex; flex-direction: column; justify-content: center; }
/* Clearly wider than tall: today's events beside the time. */
.t-clock.broad:not(.row):not(.t-time) { display: grid; grid-template-columns: auto minmax(0, 1fr); grid-template-rows: auto auto; column-gap: calc(40px * var(--k)); align-content: center; }
.t-clock.broad:not(.row):not(.t-time) .time { grid-column: 1; grid-row: 1; align-self: end; }
.t-clock.broad:not(.row):not(.t-time) .weekday { grid-column: 1; grid-row: 2; align-self: start; }
.t-clock.broad:not(.row):not(.t-time) .agenda { grid-column: 2; grid-row: 1 / span 2; margin: 0; align-self: center; font-size: max(20px, calc(21px * var(--k))); line-height: 1.5; }
.t-clock .agenda li.more, .t-today .agenda li.more { opacity: .6; }
/* Today's events in full (wall.js falls back to one line each when they do not all fit). */
.t-clock .agenda.full li, .t-today .agenda.full li { white-space: normal; overflow: visible; text-overflow: clip; line-height: 1.3; padding: .12em 0; }
.t-clock.narrow .weekday { font-size: max(17px, calc(26px * var(--k))); }
.t-clock .agenda, .t-today .agenda { font-size: max(16px, calc(20px * var(--k))); }
/* Taller than wide: the time and today's plans sit in the middle rather than at the top. */
.t-clock.tall { display: flex; flex-direction: column; justify-content: center; }
.t-clock.short:not(.wide) { display: flex; flex-direction: column; justify-content: center; }
/* The clock alone: the time and the day, centred in the tile. */
.t-time .agenda { display: none !important; }
.tile.t-time.t-clock:not(.row) { display: flex; flex-direction: column; justify-content: center; align-items: center; text-align: center; }
.t-time.row { justify-content: center; }

/* Today: the date over today's events (as on the clock); one row is the date beside them; one cell is
   the date alone, with how many events there are. */
.t-today { display: flex; flex-direction: column; justify-content: center; }
.t-today.row { flex-direction: row; }
/* Clearly wider than tall: a big date on the left, the events beside it. */
.t-today.broad:not(.row) { display: grid; grid-template-columns: auto minmax(0, 1fr); column-gap: calc(40px * var(--k)); align-items: center; }
.t-today.broad:not(.row) .lbl { display: none; }
.t-today.broad:not(.row) .big { display: flex; flex-direction: column; align-items: center; line-height: 1; }
.t-today.broad:not(.row) .big .wd, .t-today.broad:not(.row) .big .mo { font-size: calc(22px * var(--k)); font-weight: 700; text-transform: uppercase; letter-spacing: .08em; opacity: .75; }
.t-today.broad:not(.row) .big b { margin: calc(4px * var(--k)) 0; font-size: calc(84px * var(--k)); font-weight: 700; font-variant-numeric: tabular-nums; }
.t-today.broad:not(.row) .agenda { margin: 0; }
.t-today .mo { display: none; }
.t-today.broad:not(.row) .mo { display: block; }
/* Two columns and three or more rows: the big date on top, the events under it. */
.t-today.narrow.tall .lbl { display: none; }
.t-today.narrow.tall .big { display: flex; flex-direction: column; align-items: center; flex: none; margin-bottom: calc(14px * var(--k)); line-height: 1; }
.t-today.narrow.tall .big .wd { font-size: max(15px, calc(20px * var(--k))); font-weight: 700; text-transform: uppercase; letter-spacing: .08em; opacity: .75; }
.t-today.narrow.tall .big b { margin-top: calc(4px * var(--k)); font-size: calc(64px * var(--k)); font-weight: 700; font-variant-numeric: tabular-nums; }
.t-today:not(.row) .lbl { margin-bottom: calc(8px * var(--k)); font-size: max(19px, calc(26px * var(--k))); font-weight: 600; letter-spacing: 0; text-transform: none; opacity: 1; }
.t-today .big, .t-today .cnt { display: none; }
/* Each event: its dot, then its time and title, which wrap under themselves rather than under the dot. */
.t-today .agenda li { display: flex; align-items: baseline; gap: .45em; }
.t-today .agenda li > span { min-width: 0; overflow: hidden; text-overflow: ellipsis; }
.t-today .agenda.full li > span { overflow: visible; }
.t-today .agenda li i { flex: none; width: .55em; height: .55em; border-radius: 50%; transform: translateY(-.1em); }
.t-today.row .lbl { display: none; }
.t-today.row .big { display: flex; flex-direction: column; align-items: center; flex: none; line-height: 1; }
.t-today.row .big .wd { font-size: 15px; font-weight: 700; text-transform: uppercase; letter-spacing: .08em; opacity: .75; }
.t-today.row .big b { margin-top: 3px; font-size: 40px; font-weight: 700; font-variant-numeric: tabular-nums; }
.t-today.row .agenda { margin: 0; flex: 1; font-size: 21px; line-height: 1.35; }
/* A long row: the events side by side. */
.t-today.row.roomy .agenda { display: flex; flex-wrap: wrap; align-content: center; column-gap: 30px; font-size: 23px; }
.t-today.tiny .agenda { display: none; }
.t-today.tiny .big b { font-size: 38px; }
.t-today.tiny .cnt { display: block; margin-top: 3px; font-size: 12px; opacity: .8; }

/* Weather: one row is the icon, temperature and conditions (and high/low when there is room); two
   rows drop the details, unless roomy, which puts them beside. */
.t-weather.row { flex-direction: row; }
.t-weather.row .now { display: contents; }
.t-weather.row .temp { order: 2; font-size: 52px; }
.t-weather.row .cond { display: contents; }
.t-weather.row .icon { order: 1; width: 50px; height: 50px; }
.t-weather.row .label { order: 3; font-size: 22px; }
.t-weather.row .sub { order: 4; margin: 0; font-size: 22px; opacity: .8; }
.t-weather.row .stats { display: none; }
/* A long row: the details line up on the right. */
.t-weather.row.roomy .stats { order: 5; display: flex; gap: 26px; margin: 0 0 0 auto; font-size: 19px; line-height: 1.25; }
.t-weather.row.roomy .stats div { flex-direction: column; align-items: flex-start; gap: 0; }
.t-weather.row.roomy .stats dt { font-size: 15px; text-transform: uppercase; letter-spacing: .06em; }
.t-weather.row.roomy[data-w="5"] .stats div:nth-child(n+2), .t-weather.row.roomy[data-w="6"] .stats div:nth-child(n+3), .t-weather.row.roomy[data-w="7"] .stats div:nth-child(n+4) { display: none; }
.t-weather.row.narrow .sub, .t-weather.row.narrow .label { display: none; }
.t-weather.row:not(.roomy) .sub { display: none; }
.t-weather.short .stats { display: none; }
.t-weather.short { justify-content: center; }
/* Two rows and roomy, or at least twice as wide as tall: the details in a column beside the weather. */
.t-weather.short.roomy, .t-weather.wide:not(.row):not(.short) { display: grid; grid-template-columns: auto minmax(0, 1fr); grid-template-rows: auto auto; column-gap: calc(48px * var(--k)); align-content: center; }
.t-weather.short.roomy .now, .t-weather.wide:not(.row):not(.short) .now { grid-column: 1; grid-row: 1; gap: calc(24px * var(--k)); }
.t-weather.short.roomy .sub, .t-weather.wide:not(.row):not(.short) .sub { grid-column: 1; grid-row: 2; }
.t-weather.short.roomy .stats, .t-weather.wide:not(.row):not(.short) .stats { display: block; grid-column: 2; grid-row: 1 / span 2; margin: 0; align-self: center; justify-self: end; width: 100%; max-width: calc(330px * var(--k)); line-height: 1.45; }
.t-weather.short.roomy .stats { font-size: 20px; max-width: 300px; }
.t-weather.narrow:not(.row) .stats { font-size: 17px; }
/* Two columns and three or more rows: the condition gets its own line under the temperature. */
.t-weather.narrow.tall .now { flex-wrap: wrap; align-items: center; }
.t-weather.narrow.tall .cond { display: contents; }
.t-weather.narrow.tall .label { order: 3; flex-basis: 100%; margin-top: calc(6px * var(--k)); font-size: 18px; }
/* Taller than wide: everything gathers in the middle instead of leaving a gap above the details. */
.t-weather.tall { justify-content: center; }
.t-weather.tall .stats { margin-top: calc(22px * var(--k)); }

/* Forecast: one row lays the seven days out in a line; two rows give each day a column. */
.t-forecast.row .lbl, .t-forecast.short .lbl { display: none; }
.t-forecast.row ol { flex: 1; display: flex; justify-content: space-between; gap: 8px; }
.t-forecast.row li { display: flex; flex-direction: column; align-items: center; gap: 4px; font-size: 16px; line-height: 1; }
.t-forecast.row li svg { width: 26px; height: 26px; }
.t-forecast.row li b { font-size: 21px; }
.t-forecast.row li .lo { display: none; }
.t-forecast.row.roomy li { font-size: 18px; gap: 5px; }
.t-forecast.row.roomy li svg { width: 30px; height: 30px; }
.t-forecast.row.roomy li b { font-size: 24px; }
.t-forecast.short { display: flex; align-items: center; }
.t-forecast.short ol { flex: 1; display: grid; grid-template-columns: repeat(7, minmax(0, 1fr)); gap: 6px; }
.t-forecast.short li { display: flex; flex-direction: column; align-items: center; gap: 10px; font-size: 21px; line-height: 1; }
.t-forecast.short li svg { width: 36px; height: 36px; }
.t-forecast.short li b { font-size: 24px; }
.t-forecast.short li .lo { margin-top: -6px; font-size: 19px; }
.t-forecast.narrow:not(.short):not(.row) li { grid-template-columns: 2.6em 1fr auto; font-size: 19px; }
.t-forecast.narrow:not(.short):not(.row) li .lo { display: none; }
.t-forecast.narrow:not(.short):not(.row) li svg { width: 22px; height: 22px; }
/* Clearly wider than tall: each day gets a column, like the two-row version but larger. */
.t-forecast.broad:not(.row):not(.short) { display: flex; flex-direction: column; container-type: inline-size; }
.t-forecast.broad:not(.row):not(.short) ol { flex: 1; display: grid; grid-template-columns: repeat(7, minmax(0, 1fr)); align-content: center; gap: 8px; }
/* Seven columns share the width, so type is sized by the tile's width (cqw) as well as its scale.
   Browsers without container units (Safari before 16, so iPadOS 15) keep the first, scale-only value. */
.t-forecast.broad:not(.row):not(.short) li { display: flex; flex-direction: column; align-items: center; gap: calc(10px * var(--k)); gap: min(calc(14px * var(--k)), 2.8cqw); font-size: calc(18px * var(--k)); font-size: min(calc(24px * var(--k)), 5cqw); line-height: 1; }
.t-forecast.broad:not(.row):not(.short) li svg { width: calc(36px * var(--k)); height: calc(36px * var(--k)); width: min(calc(48px * var(--k)), 9cqw); height: min(calc(48px * var(--k)), 9cqw); }
.t-forecast.broad:not(.row):not(.short) li b { font-size: calc(24px * var(--k)); font-size: min(calc(30px * var(--k)), 6.2cqw); }
.t-forecast.broad:not(.row):not(.short) li .lo { margin-top: calc(-6px * var(--k)); font-size: calc(18px * var(--k)); font-size: min(calc(24px * var(--k)), 5cqw); }
.t-forecast.broad:not(.row):not(.short):not([data-h="3"]) li .pp { display: block; font-size: calc(14px * var(--k)); font-size: min(calc(19px * var(--k)), 3.8cqw); opacity: .6; }
.t-forecast.broad:not(.row):not(.short):not([data-h="3"]) li .pp:empty::before { content: '–'; }
/* Taller than wide: the seven days spread down the tile. */
.t-forecast.tall { display: flex; flex-direction: column; }
.t-forecast.tall ol { flex: 1; display: flex; flex-direction: column; justify-content: space-evenly; }

/* Weather and forecast: the weather now, with the days ahead under it (square or taller) or beside
   it (wider); fitTile keeps as many days as fit, and drops the details first when they crowd out the days. */
.t-weatherweek { display: flex; flex-direction: column; }
.t-weatherweek > .t-weather, .t-weatherweek > .t-forecast { padding: 0; min-width: 0; }
.t-weatherweek > .t-weather { flex: none; }
.t-weatherweek > .t-forecast { flex: 1; display: flex; flex-direction: column; min-height: 0; margin-top: calc(16px * var(--k)); }
.t-weatherweek .t-forecast .lbl { display: none; }
.t-weatherweek .t-forecast ol { flex: 1; display: flex; flex-direction: column; justify-content: space-evenly; }
.t-weatherweek .t-weather .stats { margin-top: calc(14px * var(--k)); }
.t-weatherweek.bare .t-weather .stats { display: none; }
.t-weatherweek .t-forecast li.off { display: none !important; }
.t-weatherweek .t-forecast li .pp, .t-weatherweek.row .t-forecast li .lo { display: none; }
.t-weatherweek.short .t-forecast li .lo, .t-weatherweek.broad .t-forecast li .lo { margin-top: -4px; font-size: .8em; }
/* Wider: the days stand in columns beside the weather. */
.t-weatherweek.broad { flex-direction: row; align-items: center; gap: calc(34px * var(--k)); }
.t-weatherweek.broad > .t-weather { width: calc(240px * var(--k)); }
.t-weatherweek.broad > .t-forecast { margin: 0; align-self: stretch; justify-content: center; }
.t-weatherweek.broad .t-forecast ol { flex: none; display: grid; grid-auto-flow: column; grid-auto-columns: minmax(calc(62px * var(--k)), 1fr); gap: 6px; }
.t-weatherweek.broad .t-forecast li { display: flex; flex-direction: column; align-items: center; gap: calc(14px * var(--k)); font-size: calc(24px * var(--k)); line-height: 1; }
.t-weatherweek.broad .t-forecast li svg { width: calc(46px * var(--k)); height: calc(46px * var(--k)); }
.t-weatherweek.broad .t-forecast li b { font-size: calc(29px * var(--k)); }
/* Wider than tall but not twice as wide (and three rows or more): the weather on top, its details in a
   strip, the days in columns underneath. */
.t-weatherweek.broad:not(.wide):not(.short):not(.row) { flex-direction: column; align-items: stretch; justify-content: center; gap: calc(22px * var(--k)); }
.t-weatherweek.broad:not(.wide):not(.short):not(.row) > .t-weather { width: auto; display: grid; grid-template-columns: auto auto minmax(0, 1fr); grid-template-rows: auto auto; column-gap: calc(22px * var(--k)); align-items: center; }
.t-weatherweek.broad:not(.wide):not(.short):not(.row) .t-weather .now { display: contents; }
.t-weatherweek.broad:not(.wide):not(.short):not(.row) .t-weather .temp { grid-column: 1; grid-row: 1; }
.t-weatherweek.broad:not(.wide):not(.short):not(.row) .t-weather .cond { grid-column: 2; grid-row: 1 / span 2; margin: 0; }
.t-weatherweek.broad:not(.wide):not(.short):not(.row) .t-weather .sub { grid-column: 1; grid-row: 2; margin: 0; }
.t-weatherweek.broad:not(.wide):not(.short):not(.row) .t-weather .stats { grid-column: 3; grid-row: 1 / span 2; margin: 0; display: flex; justify-content: space-evenly; gap: calc(20px * var(--k)); line-height: 1.3; }
.t-weatherweek.broad:not(.wide):not(.short):not(.row) .t-weather .stats div { flex-direction: column; align-items: center; gap: 0; }
.t-weatherweek.broad:not(.wide):not(.short):not(.row) .t-weather .stats dt { font-size: .75em; text-transform: uppercase; letter-spacing: .06em; }
.t-weatherweek.broad:not(.wide):not(.short):not(.row) > .t-forecast { flex: none; }
.t-weatherweek.broad:not(.wide):not(.short):not(.row) .t-forecast ol { grid-auto-columns: minmax(calc(56px * var(--k)), 1fr); }
/* Two rows: the temperature and today's high and low, then the days. */
.t-weatherweek.short > .t-weather { width: auto; justify-content: center; }
.t-weatherweek.short .t-weather .now { gap: calc(18px * var(--k)); }
.t-weatherweek.short .t-weather .stats { display: none; }
.t-weatherweek.short .t-forecast ol { grid-auto-columns: minmax(58px, 1fr); }
.t-weatherweek.short .t-forecast li { gap: 10px; font-size: 21px; }
.t-weatherweek.short .t-forecast li svg { width: 36px; height: 36px; }
.t-weatherweek.short .t-forecast li b { font-size: 24px; }
/* One row: the icon and the temperature, then the days. */
.t-weatherweek.row { gap: 22px; }
.t-weatherweek.row > .t-weather { flex-direction: row; }
.t-weatherweek.row .t-weather .now { flex-direction: row-reverse; align-items: center; gap: 10px; }
.t-weatherweek.row .t-weather .cond { margin: 0; }
.t-weatherweek.row .t-weather .icon { width: 50px; height: 50px; }
.t-weatherweek.row .t-weather .temp { font-size: 52px; }
.t-weatherweek.row .t-weather .label, .t-weatherweek.row .t-weather .sub, .t-weatherweek.row .t-weather .stats { display: none; }
.t-weatherweek.row .t-forecast ol { grid-auto-columns: minmax(50px, 1fr); }
.t-weatherweek.row .t-forecast li { gap: 4px; font-size: 16px; }
.t-weatherweek.row .t-forecast li svg { width: 26px; height: 26px; }
.t-weatherweek.row .t-forecast li b { font-size: 21px; }

/* Coming up: one row shows only what is next. */
.t-agenda.row .lbl { display: none; }
.t-agenda.row ol { flex: 1; display: flex; align-items: center; gap: 36px; overflow: hidden; font-size: 26px; line-height: 1.2; }
.t-agenda.row .item { display: flex; align-items: center; gap: 10px; flex: none; }
.t-agenda.row .item:last-child { flex: 0 1 auto; min-width: 0; }
.t-agenda.row .item .what { min-width: 0; overflow: hidden; text-overflow: ellipsis; }
.t-agenda.row ol.measure .item { flex: none; }
.t-agenda.row .item .when { flex: none; font-weight: 700; opacity: .75; margin-right: 6px; }
.t-agenda .item i { flex: none; }
.t-agenda ol { font-size: max(15px, calc(21px * var(--k))); }
.t-agenda:not(.row) { display: flex; flex-direction: column; }
.t-agenda:not(.row) ol { flex: 1; min-height: 0; }
/* Clearly wider than tall: the days flow into columns (fitTile trims what runs past the last). */
.t-agenda.broad:not(.row) ol { column-count: 2; column-gap: calc(48px * var(--k)); column-fill: auto; }
.t-agenda.broad.wide:not(.row)[data-w="8"] ol, .t-agenda.broad.wide:not(.row)[data-w="9"] ol { column-count: 3; }
.t-agenda.broad:not(.row) .dayhead { break-after: avoid; }
.t-agenda.broad:not(.row) .item { break-inside: avoid; }

/* To-do: smaller tiles keep the list readable and let "+N more" say the rest. */
.t-todo ul { font-size: max(15px, calc(22px * var(--k))); }
.t-todo.narrow ul { font-size: 18px; }

/* Meals: one row is tonight's dinner; two rows are tonight and tomorrow. */
.t-meals ol { font-size: max(15px, calc(21px * var(--k))); }
.t-meals.row .lbl { display: none; }
.t-meals.row ol { flex: 1; display: flex; gap: 40px; font-size: 28px; line-height: 1.2; }
.t-meals.row li { min-width: 0; }
.t-meals.row li:not(:last-child) { flex: none; }
.t-meals.row li { display: flex; align-items: baseline; gap: 14px; }
.t-meals.row li .d { font-size: 20px; text-transform: uppercase; letter-spacing: .08em; opacity: .7; }
.t-meals.row li .m { overflow: hidden; text-overflow: ellipsis; }
.t-meals.short li, .t-meals.row li { grid-template-columns: auto 1fr; font-weight: 400; }
.t-meals.short { display: flex; flex-direction: column; }
.t-meals.short ol { flex: 1; display: flex; flex-direction: column; justify-content: center; font-size: 28px; line-height: 1.45; }
.t-meals.narrow:not(.short):not(.row) ol { font-size: 18px; }
/* Taller than wide: the week spreads down the tile. Clearly wider than tall: two columns. */
.t-meals.tall { display: flex; flex-direction: column; }
.t-meals.tall ol { flex: 1; display: flex; flex-direction: column; justify-content: space-evenly; }
.t-meals.broad:not(.short):not(.row) { display: flex; flex-direction: column; }
.t-meals.broad:not(.short):not(.row) ol { margin: auto 0; column-count: 2; column-gap: calc(40px * var(--k)); }
.t-meals.broad:not(.short):not(.row) li { break-inside: avoid; }
.t-meals.short li { gap: .7em; }
.t-meals.short li .d { min-width: 4.6em; }
.t-meals.short li.today .m { font-weight: 700; }
/* A wide tile: the week in seven columns, each night's dinner under its day. */
.t-meals.cols { display: flex; flex-direction: column; }
.t-meals.cols ol { flex: 1; display: grid; grid-template-columns: repeat(7, minmax(0, 1fr)); column-gap: calc(14px * var(--k)); align-content: center; column-count: auto; margin: 0; }
.t-meals.cols li { display: flex; flex-direction: column; align-items: center; gap: .35em; text-align: center; white-space: normal; overflow: visible; text-overflow: clip; line-height: 1.2; }
.t-meals.cols li .d { min-width: 0; font-size: .8em; text-transform: uppercase; letter-spacing: .06em; }
.t-meals.cols li .m { overflow: hidden; display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 3; overflow-wrap: break-word; }
.t-meals.cols li.today .m { font-weight: 700; }
.t-meals.cols.short ol { font-size: 21px; }
.t-meals.cols:not(.short) ol { grid-template-columns: repeat(4, minmax(0, 1fr)); row-gap: calc(22px * var(--k)); }

/* Countdown: one row puts it all on a line, the number first; two rows wide put the words beside it. */
.t-countdown.row { flex-direction: row; justify-content: center; }
.t-countdown.row .big { font-size: 54px; flex: none; }
.t-countdown.row .big small { font-size: 20px; }
.t-countdown.row .title { margin: 0; font-size: 26px; min-width: 0; flex: 0 1 auto; }
.t-countdown.row .when { margin: 0 0 0 10px; font-size: 20px; flex: none; opacity: .7; }
.t-countdown.row:not(.roomy) .when { display: none; }
.t-countdown:not(.row) { align-items: center; text-align: center; }
.t-countdown > * { flex-shrink: 0; }
.t-countdown:not(.row) .title { max-width: 100%; }
/* Clearly wider than tall: the words beside the number. */
.t-countdown.broad:not(.row) { display: grid; grid-template-columns: auto minmax(0, auto); grid-template-rows: auto auto; column-gap: calc(34px * var(--k)); align-content: center; justify-content: center; text-align: left; }
.t-countdown.broad:not(.row) .big { grid-row: 1 / span 2; align-self: center; }
.t-countdown.broad:not(.row) .title { margin: 0; align-self: end; font-size: max(22px, calc(30px * var(--k))); }
.t-countdown.broad:not(.row) .when { align-self: start; font-size: max(17px, calc(20px * var(--k))); }
.t-countdown .when { font-size: max(15px, calc(18px * var(--k))); }

/* Note: the text shrinks to fit (wall.js); one row is a single line. */
.t-note .text { max-height: 100%; line-height: 1.2; }
.t-note.row .text { line-height: 1.15; }

/* QR: one row puts the label beside the code; a one-cell-wide tile is the code alone. */
.t-qr.row { flex-direction: row; justify-content: flex-start; padding: 14px 24px 14px 14px; }
.t-qr.row.roomy, .t-wifi.row.roomy { justify-content: center; gap: 22px; }
.t-qr.row .code { height: 100%; flex: none; }
.t-qr.row .label { font-size: 23px; text-align: left; white-space: normal; line-height: 1.2; }
.t-qr.row.narrow { justify-content: center; padding: 10px; }
.t-qr.row.narrow .label { display: none; }
/* Clearly wider than tall: the label sits beside the code, larger. */
.t-qr.broad:not(.row) { flex-direction: row; justify-content: center; gap: calc(30px * var(--k)); }
.t-qr.broad:not(.row) .code { height: 100%; flex: 0 1 auto; max-width: 55%; }

/* Wi-Fi: the code (drawn in the tile's text colour) with the network name and password under it, or
   beside it on a one-row or wide tile; a one-column tile shows the code alone. */
.t-wifi { display: flex; flex-direction: column; align-items: center; justify-content: center; gap: calc(8px * var(--k)); padding: calc(18px * var(--k)); }
.t-wifi .code { flex: 1 1 auto; min-height: 0; max-width: 100%; aspect-ratio: 1; }
.t-wifi .code svg { display: block; width: 100%; height: 100%; }
.t-wifi.empty .code svg { fill: none; stroke: currentColor; stroke-width: 1.8; stroke-linecap: round; opacity: .55; }
.t-wifi.empty .code svg circle { fill: currentColor; stroke: none; }
.t-wifi.empty .code { flex: 0 1 auto; width: 46%; }
.t-wifi .label { flex: none; display: flex; flex-direction: column; align-items: center; max-width: 100%; line-height: 1.2; text-align: center; }
.t-wifi .ssid, .t-wifi .pw { max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.t-wifi .ssid { font-size: calc(19px * var(--k)); font-weight: 700; }
.t-wifi .pw { font-size: calc(16px * var(--k)); opacity: .8; font-variant-numeric: tabular-nums; }
.t-wifi .pw:empty { display: none; }
.t-wifi[data-w="1"] .label { display: none; }
.t-wifi.row { flex-direction: row; justify-content: flex-start; padding: 14px 24px 14px 14px; gap: 16px; }
.t-wifi.row .code { height: 100%; flex: none; }
.t-wifi.row .label { align-items: flex-start; text-align: left; min-width: 0; }
.t-wifi.row .ssid { font-size: 26px; }
.t-wifi.row .pw { font-size: 22px; }
.t-wifi.row.narrow { justify-content: center; padding: 10px; }
.t-wifi.row.narrow .label { display: none; }
.t-wifi.broad:not(.row) { flex-direction: row; gap: calc(26px * var(--k)); }
.t-wifi.broad:not(.row) .code { height: 100%; flex: 0 1 auto; max-width: 55%; }
.t-wifi.broad:not(.row) .label { align-items: flex-start; text-align: left; min-width: 0; gap: calc(4px * var(--k)); }
.t-wifi.broad:not(.row) .ssid { font-size: max(24px, calc(36px * var(--k))); }
.t-wifi.broad:not(.row) .pw { font-size: max(20px, calc(28px * var(--k))); }
.t-qr.broad:not(.row) .label { font-size: max(22px, calc(34px * var(--k))); font-weight: 600; text-align: left; white-space: normal; max-width: 45%; line-height: 1.2; opacity: .85; }
.t-qr[data-w="1"] .label { display: none; }
/* One column wide: the code keeps clear of the tile's rounded corners (43px), so none of it is cut off. */
.tile.t-qr[data-w="1"], .tile.t-wifi[data-w="1"] { padding: 14px; }

/* ---------- Night screen (wall.js): black, with a dim clock that moves every couple of minutes ---------- */
#night { position: fixed; inset: 0; z-index: 200; background: #000; cursor: none; touch-action: none; }
#night[hidden] { display: none; }
#night .nclock { position: absolute; left: 50%; top: 50%; transform: translate(-50%, -50%) rotate(var(--turn, 0deg)); text-align: center; white-space: nowrap; transition: opacity 1.5s ease; font-family: Inter, system-ui, -apple-system, "Segoe UI", Roboto, "Noto Sans", "DejaVu Sans", sans-serif; }
#night .nclock.fade { opacity: 0; }
#night .ntime { font-size: 15vmin; font-weight: 300; line-height: 1; letter-spacing: -.02em; color: #5c5c5c; font-variant-numeric: tabular-nums; }
#night .ntime span { font-size: .3em; font-weight: 400; margin-left: .25em; vertical-align: .9em; letter-spacing: 0; }
#night .nday { margin-top: 2vmin; font-size: 3.4vmin; color: #3f3f3f; }

/* ---------- The tile gallery (/demo?gallery=1): every tile at every size, at half size ---------- */
body.gallery { overflow: auto; background: #1b1714; }
body.gallery #app, body.gallery #demo-banner, body.gallery #demo-rotate { display: none; }
#gallery { padding: 30px; font-family: Inter, system-ui, -apple-system, "Segoe UI", Roboto, sans-serif; background: var(--bg); }
#gallery > section { display: flex; flex-wrap: wrap; align-items: flex-start; gap: 22px; margin-bottom: 30px; }
#gallery h2 { flex-basis: 100%; margin: 0; color: var(--ink); font-size: 22px; }
#gallery figure { margin: 0; zoom: var(--gz, .5); }
#gallery figure .tile { position: relative; transition: none; }
#gallery figcaption { margin-top: 10px; color: var(--mut); font-size: 30px; }

/* ---------- Adding an event: tap a day ---------- */
#sheet { position: absolute; inset: 0; z-index: 40; background: rgba(0,0,0,.42); display: flex; align-items: flex-end; justify-content: center; padding: 38px; }
#sheet[hidden] { display: none; }
.sheet-card { width: 100%; max-width: 1004px; background: var(--cell); color: var(--celli); border-radius: 36px; padding: 30px 36px 34px; box-shadow: 0 24px 60px rgba(0,0,0,.35); font-size: 26px; }
.sheet-head { display: flex; align-items: center; justify-content: space-between; font-size: 34px; font-weight: 700; margin-bottom: 20px; }
.sheet-head button { font: inherit; font-size: 28px; width: 64px; height: 64px; border: 0; border-radius: 50%; background: var(--other); color: var(--celli); }
#sheet-not-connected { margin: 0; font-size: 26px; line-height: 1.45; color: var(--mut); }
.sheet-input { display: flex; gap: 12px; }
#sheet-title { flex: 1; min-width: 0; font: inherit; font-size: 32px; padding: 16px 22px; border-radius: 18px; border: 2px solid var(--other); background: var(--bg); color: var(--ink); outline: none; }
#sheet-title:focus { border-color: var(--mut); }
.sheet-row { display: flex; align-items: center; gap: 16px; margin-top: 18px; flex-wrap: wrap; }
.sheet-row button { font: inherit; font-size: 24px; padding: 12px 20px; border-radius: 16px; border: 2px solid var(--other); background: var(--bg); color: var(--ink); }
.sheet-row button.on { background: var(--today); color: var(--todayi); border-color: var(--today); }
.timebox, .durbox { display: flex; align-items: center; gap: 10px; }
/* The start time: a field to tap and type into, between the half-hour steps, and an AM/PM switch. */
#sheet-time { width: 4.4em; font: inherit; font-size: 26px; font-weight: 600; text-align: center; font-variant-numeric: tabular-nums; padding: 10px 6px; border-radius: 16px; border: 2px solid var(--other); background: var(--bg); color: var(--ink); outline: none; }
#sheet-time:focus { border-color: var(--mut); }
.sheet-row .ampm { display: flex; border: 2px solid var(--other); border-radius: 16px; overflow: hidden; }
.sheet-row .ampm[hidden] { display: none; }
.sheet-row .ampm button { border: 0; border-radius: 0; padding: 12px 16px; }
.sheet-row .ampm button + button { border-left: 2px solid var(--other); }
.sheet-row .ampm button.on { border-color: var(--today); }
.durbox span, .repeatbox span { color: var(--mut); }
.repeatbox { gap: 10px; }
.repeatbox button { font-size: 22px; padding: 10px 16px; }
.timebox.off, .timebox.off ~ .durbox { opacity: .35; pointer-events: none; }
.sheet-actions { display: flex; align-items: center; justify-content: space-between; gap: 16px; margin-top: 22px; }
#sheet-msg { font-size: 24px; color: var(--mut); }
.primary { font: inherit; font-size: 26px; font-weight: 600; padding: 16px 28px; border-radius: 18px; border: 0; background: var(--today); color: var(--todayi); }
.primary:disabled { opacity: .45; }

/* A short message over the wall (offline, saved, errors). */
#notice { position: absolute; left: 50%; bottom: 60px; transform: translateX(-50%); z-index: 45; padding: 14px 26px; border-radius: 999px; background: rgba(0,0,0,.6); color: #fff; font-size: 24px; white-space: nowrap; }
#notice[hidden] { display: none; }

/* ---------- Screen chrome: fullscreen, cast, edit, settings (hidden on a display) ---------- */
#chrome { position: fixed; right: 14px; bottom: 14px; z-index: 60; display: flex; gap: 8px; opacity: 0; transition: opacity .3s; }
#chrome[hidden] { display: none; }
#chrome.show { opacity: 1; }
.cbtn { width: 44px; height: 44px; border-radius: 50%; border: 0; background: rgba(0,0,0,.55); color: #fff; font: 20px/44px system-ui, sans-serif; text-align: center; text-decoration: none; cursor: pointer; box-shadow: 0 2px 10px rgba(0,0,0,.4); }
.cbtn:hover { background: rgba(0,0,0,.8); }
.cbtn[hidden] { display: none; }

/* ---------- Editor (owner only; loaded on demand) ---------- */
#editor { position: fixed; top: 0; right: 0; bottom: 0; width: 340px; z-index: 70; overflow: auto; background: #1b1714; color: #f1ebe4; font: 14px/1.45 system-ui, -apple-system, "Segoe UI", Roboto, sans-serif; padding: 14px 16px 30px; box-shadow: -10px 0 40px rgba(0,0,0,.4); }
#editor[hidden] { display: none; }
@media (max-width: 760px) { #editor { top: auto; left: 0; width: auto; height: 300px; box-shadow: 0 -10px 40px rgba(0,0,0,.4); } }
#editor h2 { font-size: 15px; margin: 14px 0 6px; letter-spacing: .04em; text-transform: uppercase; color: #b7ab9f; }
#editor h2:first-child { margin-top: 0; }
#editor .row { display: flex; gap: 8px; flex-wrap: wrap; align-items: center; }
#editor button, #editor select, #editor input, #editor textarea { font: inherit; color: inherit; background: #2a241f; border: 1px solid #3f372f; border-radius: 8px; padding: 6px 10px; }
#editor button { cursor: pointer; }
#editor button:hover { background: #352e27; }
#editor button.on { background: #e6cfa6; color: #2a2016; border-color: #e6cfa6; font-weight: 600; }
#editor button.primary { background: #cfae7b; color: #22190f; border-color: #cfae7b; font-weight: 600; }
#editor button.danger { color: #ffb3a7; border-color: #6a3a32; }
#editor input, #editor textarea, #editor select { width: 100%; }
#editor label { display: block; margin: 8px 0 4px; color: #d8cfc4; }
/* A tile option's checkbox sits beside its words, not stretched across the panel. */
#editor input[type=checkbox] { width: auto; margin: 0; accent-color: #cfae7b; }
#editor label:has(> input[type=checkbox]) { display: flex; align-items: center; gap: 8px; cursor: pointer; }
#editor label.keep { display: flex; align-items: center; gap: 8px; margin: 10px 0 0; cursor: pointer; }
#editor label.keep input { width: auto; margin: 0; accent-color: #cfae7b; }
#editor .pal { display: grid; grid-template-columns: 1fr 1fr; gap: 6px; }
#editor .pal button { display: flex; flex-direction: column; align-items: stretch; gap: 3px; padding: 7px; text-align: left; cursor: grab; }
#editor .pal button:disabled { cursor: not-allowed; opacity: .45; }
#editor .pal button b { font-weight: 600; font-size: 13px; }
#editor .pal button small { display: block; color: #a89c8f; font-weight: 400; font-size: 12px; }
@media (pointer: fine) { #editor .pal button { touch-action: none; } }
/* Each tile type as it looks on the wall, scaled down (editor.js sizes --pw / --ph). */
#editor .pal .slot { position: relative; display: grid; place-items: center; height: 92px; border-radius: 7px; background: #2a241f; overflow: hidden; }
#editor .pal .placed { position: absolute; top: 5px; right: 5px; z-index: 2; padding: 2px 7px; border-radius: 999px; background: rgba(20, 16, 13, .78); color: #f6e8d4; font-size: 11px; font-style: normal; font-weight: 600; line-height: 1.4; pointer-events: none; }
.pv { position: relative; width: var(--pw); height: var(--ph); pointer-events: none; }
.pv .tile.preview { position: absolute; left: 0; top: 0; transform-origin: 0 0; transition: none; outline: none; cursor: inherit; }
.pv .tile.preview.t-photo { background: #5a4d42 center / cover no-repeat; }
.pv .tile.preview.t-spacer { border: 10px dashed rgba(128,118,108,.6); }
.pv.ghost { position: fixed; z-index: 90; transform: translate(-50%, -50%) scale(1.6); opacity: .92; filter: drop-shadow(0 10px 22px rgba(0,0,0,.5)); }
/* Colours: the look's own swatches, then a board of every hue, then any colour. */
#editor h3 { font-size: 13px; font-weight: 600; margin: 14px 0 6px; color: #d8cfc4; }
#editor .rl { flex: none; width: 84px; color: #b7ab9f; font-size: 13px; }
#editor .seg { display: inline-flex; }
#editor .seg button { border-radius: 0; margin-left: -1px; }
#editor .seg button:first-child { border-radius: 8px 0 0 8px; margin-left: 0; }
#editor .seg button:last-child { border-radius: 0 8px 8px 0; }
#editor .sw-row { display: flex; flex-wrap: wrap; align-items: center; gap: 5px; }
#editor .sw .none { padding: 3px 9px; font-size: 12px; }
#editor .sw .c { width: 24px; height: 24px; padding: 0; border-radius: 6px; border: 1px solid rgba(255,255,255,.2); }
#editor .sw .c.on { outline: 2px solid #e6cfa6; outline-offset: 2px; }
#editor .board { display: grid; grid-template-columns: repeat(12, minmax(0, 1fr)); gap: 3px; margin-top: 8px; }
#editor .board .c { width: auto; height: auto; aspect-ratio: 1; border-radius: 4px; }
#editor label.any { display: flex; align-items: center; gap: 8px; margin: 8px 0 0; font-size: 13px; color: #b7ab9f; }
#editor label.any input { width: 46px; height: 28px; padding: 1px; cursor: pointer; }
#editor .msg { margin-top: 10px; color: #ffd28f; min-height: 1.4em; }
#editor .items li { display: flex; gap: 6px; margin-bottom: 4px; }
#editor .items { list-style: none; padding: 0; margin: 0; }
#editor .hint { color: #a89c8f; font-size: 13px; }
/* While editing, a tile lets its handles out past its edges (the photo keeps its rounded corners), and
   tiles pushed aside by a drag glide to their new places; the tile being dragged follows the pointer. */
body.editing .tile { outline: 2px dashed rgba(255,255,255,.45); outline-offset: -2px; cursor: move; overflow: visible; transition: left .18s var(--ease), top .18s var(--ease), width .18s var(--ease), height .18s var(--ease); }
body.editing .tile.dragging { transition: none; }
body.editing .t-photo .photo { border-radius: inherit; overflow: hidden; }
body.editing .tile.sel { outline: 3px solid #e6cfa6; z-index: 6; }
body.editing .tile * { pointer-events: none; }
/* Resize grips straddle both bottom corners, and the remove button the top right corner, so even a
   one-cell tile can still be grabbed in the middle. Their grab area stays about a fingertip on screen
   (--scale is the stage's scale). They show on the selected tile, and on hover with a mouse. */
body.editing .grip {
  --g: max(44px, calc(34px / var(--scale, 1)));
  position: absolute; bottom: calc(var(--g) * -.4); width: var(--g); height: var(--g); z-index: 9;
  cursor: nwse-resize; pointer-events: auto !important; touch-action: none;
}
body.editing .grip.right { right: calc(var(--g) * -.4); }
body.editing .grip.left { left: calc(var(--g) * -.4); cursor: nesw-resize; }
/* A one-cell tile keeps most of each grip outside it, so its middle stays free to grab. */
body.editing .tile.tiny .grip { bottom: calc(var(--g) * -.62); }
body.editing .tile.tiny .grip.right { right: calc(var(--g) * -.62); }
body.editing .tile.tiny .grip.left { left: calc(var(--g) * -.62); }
body.editing .grip::after {
  content: ''; position: absolute; bottom: 40%; width: 34%; height: 34%;
  border-bottom: max(4px, calc(3px / var(--scale, 1))) solid rgba(255,255,255,.95); filter: drop-shadow(0 0 2px rgba(0,0,0,.8));
}
body.editing .grip.right::after { right: 40%; border-right: max(4px, calc(3px / var(--scale, 1))) solid rgba(255,255,255,.95); border-radius: 0 0 6px 0; }
body.editing .grip.left::after { left: 40%; border-left: max(4px, calc(3px / var(--scale, 1))) solid rgba(255,255,255,.95); border-radius: 0 0 0 6px; }
body.editing .tile:not(.sel) .grip, body.editing .tile:not(.sel) .tile-x { display: none; }
@media (hover: hover) {
  body.editing .tile:hover { z-index: 6; }
  body.editing .tile:hover .grip { display: block; }
  body.editing .tile:hover .tile-x { display: grid; }
}
body.editing .tile.bad { outline-color: #ff6b6b; }
/* A remove button on every tile; a tile dragged off the wall; where a tile from the palette would land. */
.tile-x { display: none; }
body.editing .tile-x {
  --x: max(40px, calc(28px / var(--scale, 1)));
  /* Mostly outside the tile's corner, so it never covers the part of a small tile you grab. */
  position: absolute; right: calc(var(--x) * -.62); top: calc(var(--x) * -.62); z-index: 10; width: var(--x); height: var(--x); padding: 0; border: 0; border-radius: 50%;
  display: grid; place-items: center; background: rgba(20,16,12,.75); color: #fff; cursor: pointer; pointer-events: auto !important;
  box-shadow: 0 2px 10px rgba(0,0,0,.45);
}
body.editing .tile-x:hover { background: #b3382c; }
.tile-x svg { width: 46%; height: 46%; fill: none; stroke: currentColor; stroke-width: 2.8; stroke-linecap: round; }
/* Zooming in on the wall while editing (pinch on a phone): the wall takes every touch, and a button
   zooms back out. */
body.editing #app { touch-action: none; }
#ed-fit { position: fixed; left: 50%; top: 14px; transform: translateX(-50%); z-index: 60; padding: 10px 18px; border: 0; border-radius: 999px; background: #e6cfa6; color: #2a2016; font: 600 15px system-ui, sans-serif; box-shadow: 0 4px 16px rgba(0,0,0,.4); cursor: pointer; }
#ed-fit[hidden] { display: none; }
body.editing .tile.leaving { opacity: .4; outline: 4px solid #ff6b6b; }
body.editing .tile.leaving::after {
  content: 'Let go to remove'; position: absolute; left: 50%; top: 50%; transform: translate(-50%, -50%); z-index: 11;
  padding: 12px 22px; border-radius: 999px; background: #b3382c; color: #fff; font: 600 28px system-ui, sans-serif; white-space: nowrap;
}
#drop-target { position: absolute; z-index: 8; border-radius: var(--r); pointer-events: none; border: 5px dashed #e6cfa6; background: rgba(230,207,166,.2); }
#drop-target.bad { border-color: #ff6b6b; background: rgba(255,107,107,.15); }
#drop-target[hidden] { display: none; }
#gridlines { position: absolute; inset: 0; pointer-events: none; z-index: 1; }
#gridlines div { position: absolute; border: 1px dashed rgba(255,255,255,.14); border-radius: 10px; }

/* The demo's invitation: a pill at the bottom of the screen, outside the stage. */
#demo-banner {
  position: fixed; left: 50%; bottom: 14px; transform: translateX(-50%); z-index: 65; max-width: calc(100vw - 120px);
  padding: 9px 16px; border-radius: 999px; background: rgba(255,252,247,.94); color: #3a2f26; text-decoration: none;
  font: 14px/1.35 system-ui, -apple-system, "Segoe UI", Roboto, sans-serif; box-shadow: 0 6px 24px rgba(0,0,0,.35);
}
#demo-banner span { color: #8a5a2b; font-weight: 600; white-space: nowrap; }
body.editing #demo-banner { display: none; }

/* ---------- Removing a photo: a trash button in the photo's menu, then a question ---------- */
.tool {
  position: absolute; left: 22px; top: 22px; width: 64px; height: 64px; border: 0; border-radius: 50%; padding: 0;
  background: rgba(0,0,0,.45); color: #fff; box-shadow: 0 2px 10px rgba(0,0,0,.4); cursor: pointer; display: grid; place-items: center;
}
.tool svg { width: 30px; height: 30px; fill: none; stroke: currentColor; stroke-width: 1.8; stroke-linecap: round; stroke-linejoin: round; }
.tool:active { background: rgba(0,0,0,.7); }
.t-photo.confirming .menu-item:not(.tool) { opacity: 0; pointer-events: none; }
.confirm {
  position: absolute; left: 50%; top: 50%; transform: translate(-50%, -50%); z-index: 6; width: min(86%, 520px);
  padding: 30px 32px 28px; border-radius: 30px; text-align: center; color: #fff;
  background: rgba(24,19,15,.82); box-shadow: 0 20px 60px rgba(0,0,0,.45); backdrop-filter: blur(8px); -webkit-backdrop-filter: blur(8px);
}
.confirm[hidden] { display: none; }
.confirm p { margin: 0 0 8px; font-size: 30px; font-weight: 700; line-height: 1.2; }
.confirm small { display: block; font-size: 19px; line-height: 1.4; opacity: .78; }
.confirm-actions { display: flex; justify-content: center; gap: 14px; margin-top: 22px; }
.confirm-actions button { font: 600 23px/1 Inter, system-ui, sans-serif; padding: 16px 28px; border-radius: 999px; cursor: pointer; }
.confirm-actions .no { background: transparent; color: #fff; border: 2px solid rgba(255,255,255,.5); }
.confirm-actions .yes { background: #b4493b; color: #fff; border: 2px solid #b4493b; }
.confirm-actions .yes:disabled { opacity: .6; }

/* Shown over the wall when its subscription has ended (wall.js showPaused). */
#paused { position: fixed; inset: 0; z-index: 80; display: grid; place-items: center; background: rgba(20,16,13,.88); color: #f3ede6; font: 18px/1.5 system-ui, -apple-system, "Segoe UI", Roboto, sans-serif; text-align: center; padding: 24px; }
#paused b { display: block; font-size: 28px; margin-bottom: 8px; }
#paused span { display: block; max-width: 28em; opacity: .8; }

/* The demo's rotate button: always in reach at the top right, outside the stage. */
#demo-rotate {
  position: fixed; top: 14px; right: 14px; z-index: 65; display: inline-flex; align-items: center; gap: 8px;
  padding: 9px 15px 9px 12px; border: 0; border-radius: 999px; cursor: pointer;
  background: rgba(255,252,247,.94); color: #3a2f26; font: 600 14px/1 system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
  box-shadow: 0 6px 24px rgba(0,0,0,.35);
}
#demo-rotate svg { width: 18px; height: 18px; fill: none; stroke: #8a5a2b; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; }
#demo-rotate:hover { background: #fff; }
body.editing #demo-rotate { display: none; }

/* ---------- One cell (1x1) ----------
   The smallest version of a tile: one thing, centred. A single cell is also a `row` and `narrow`, so
   these rules come last and name all three classes to win over the one-row layouts above. The QR
   codes keep their own one-cell layout. */
.tile.tiny.row.narrow:not(.t-qr):not(.t-wifi) { flex-direction: column; justify-content: center; align-items: center; text-align: center; gap: 2px; padding: 8px; white-space: normal; }
.tile.tiny.row.narrow .lbl { display: none; }
.t-clock.tiny.row.narrow .time { font-size: 30px; letter-spacing: -.02em; }
.t-clock.tiny.row.narrow .time .ampm { display: none; }
.t-clock.tiny.row.narrow .weekday { display: block; margin: 0; font-size: 15px; font-weight: 600; opacity: .8; }
.t-clock.tiny.row.narrow .agenda { display: none; }
.t-weather.tiny.row.narrow { gap: 0; }
.t-weather.tiny.row.narrow .icon { width: 42px; height: 42px; }
.t-weather.tiny.row.narrow .temp { font-size: 30px; }
.t-weather.tiny.row.narrow .label, .t-weather.tiny.row.narrow .sub { display: none; }
.t-agenda.tiny.row.narrow ol { flex: none; width: 100%; font-size: 13px; line-height: 1.2; }
.t-agenda.tiny.row.narrow .next { display: flex; flex-direction: column; align-items: center; gap: 1px; }
.t-agenda.tiny.row.narrow .next .when { font-size: 11px; font-weight: 700; text-transform: uppercase; letter-spacing: .06em; opacity: .7; }
.t-agenda.tiny.row.narrow .next b { font-size: 19px; font-weight: 700; font-variant-numeric: tabular-nums; }
.t-agenda.tiny.row.narrow .next .what { max-width: 100%; font-size: 12px; overflow: hidden; display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2; overflow-wrap: anywhere; }
.t-agenda.tiny.row.narrow .next .what i { display: inline-block; width: .6em; height: .6em; border-radius: 50%; margin-right: .3em; }
.t-agenda.tiny.row.narrow .none { font-size: 12px; white-space: normal; }
.t-countdown.tiny.row.narrow .big { font-size: 34px; }
.t-countdown.tiny.row.narrow .big small { display: block; margin: 1px 0 0; font-size: 12px; }
.t-countdown.tiny.row.narrow .title { margin: 2px 0 0; max-width: 100%; font-size: 11px; opacity: .8; }
.t-countdown.tiny.row.narrow .when { display: none; }
.t-meals.tiny.row.narrow ol { flex: none; width: 100%; font-size: 15px; line-height: 1.15; }
.t-meals.tiny.row.narrow li { display: flex; flex-direction: column; align-items: center; gap: 3px; white-space: normal; }
.t-meals.tiny.row.narrow li .d { font-size: 11px; letter-spacing: .06em; }
.t-meals.tiny.row.narrow li .m { font-weight: 700; overflow: hidden; display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 3; overflow-wrap: anywhere; }

/* ---------- Sunrise and sunset ---------- */
.t-sun { display: flex; flex-direction: column; justify-content: center; align-items: center; gap: calc(14px * var(--k)); }
.t-sun .ic, .t-bins .ic { display: block; flex: none; }
.t-sun svg { display: block; width: 100%; height: 100%; fill: none; stroke: currentColor; stroke-width: 2.6; stroke-linecap: round; stroke-linejoin: round; }
.t-sun .next { display: none; }
.t-sun .both { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: calc(12px * var(--k)); }
.t-sun .both li { display: grid; grid-template-columns: auto 1fr; grid-template-rows: auto auto; column-gap: calc(14px * var(--k)); align-items: center; }
.t-sun .both .ic { grid-row: 1 / span 2; width: calc(60px * var(--k)); height: calc(60px * var(--k)); }
.t-sun .both .nm { font-size: calc(18px * var(--k)); opacity: .75; }
.t-sun .both b { font-size: calc(40px * var(--k)); font-weight: 700; line-height: 1.05; font-variant-numeric: tabular-nums; white-space: nowrap; }
.t-sun .both li:not(.on) { opacity: .7; }
.t-sun .len { font-size: calc(18px * var(--k)); opacity: .7; text-align: center; }
.t-sun.short:not(.roomy) .len { display: none; }
/* At least twice as wide as tall, and five columns or more: sunrise and sunset side by side. */
.t-sun.wide.roomy:not(.row) .both { flex-direction: row; gap: calc(34px * var(--k)); }
.t-sun.row { flex-direction: row; justify-content: center; }
.t-sun.row .both { flex-direction: row; gap: 22px; }
.t-sun.row.narrow .both li:not(.on) { display: none; }
.t-sun.row .both li { grid-template-columns: auto auto; }
.t-sun.row .both .ic { grid-row: auto; width: 34px; height: 34px; }
.t-sun.row .both .nm { display: none; }
.t-sun.row .both b { font-size: 24px; }
.t-sun.row .len { display: none; }
.t-sun.row.roomy .len { display: block; font-size: 19px; }
.t-sun.row.roomy { justify-content: space-evenly; }
.t-sun.row.roomy .both { gap: 40px; }
.t-sun.row.roomy .both .ic { width: 40px; height: 40px; }
.t-sun.row.roomy .both b { font-size: 28px; }
.t-sun.tiny.row.narrow .both, .t-sun.tiny.row.narrow .len { display: none; }
.t-sun.tiny.row.narrow .next { display: flex; flex-direction: column; align-items: center; gap: 1px; }
.t-sun.tiny.row.narrow .next .ic { width: 46px; height: 46px; margin-bottom: -4px; }
.t-sun.tiny.row.narrow .next .tm { font-size: 15px; font-variant-numeric: tabular-nums; white-space: nowrap; }
.t-sun.tiny.row.narrow .next .lb { font-size: 11px; opacity: .75; }
.t-sun.empty .both, .t-sun.empty .len { display: none; }
.t-sun.empty .next { display: flex; flex-direction: column; align-items: center; gap: 4px; text-align: center; }
.t-sun.empty .next .ic { width: calc(46px * var(--k)); height: calc(46px * var(--k)); opacity: .6; }
.t-sun.empty .next .lb { font-size: calc(16px * var(--k)); opacity: .75; }

/* ---------- Moon ---------- */
.t-moon { display: flex; flex-direction: column; align-items: center; justify-content: center; gap: calc(12px * var(--k)); text-align: center; }
.t-moon .disc { flex: none; height: calc(110px * var(--k)); aspect-ratio: 1; }
.t-moon .disc svg { display: block; width: 100%; height: 100%; }
.t-moon .shade { fill: currentColor; opacity: .16; }
.t-moon .lit { fill: currentColor; }
.t-moon .rim { fill: none; }
/* The light look's dark ink would make a full moon a black disc: there the lit part is the theme's day
   squares' colour (its lightest), inside a ring of the tile's text colour. */
[data-look="light"] .t-moon .lit { fill: var(--cell, #fff); }
[data-look="light"] .t-moon .shade { opacity: .2; }
[data-look="light"] .t-moon .rim { stroke: currentColor; stroke-width: 3; }
.t-moon .txt { display: flex; flex-direction: column; gap: 3px; min-width: 0; }
.t-moon .nm { font-size: calc(26px * var(--k)); white-space: nowrap; }
.t-moon .nx { font-size: calc(18px * var(--k)); opacity: .75; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.t-moon:not(.row) .nx { white-space: normal; }
.t-moon.tall .disc { height: auto; width: min(70%, calc(130px * var(--k))); }
/* Wider than tall: the moon beside its words. */
.t-moon.landscape:not(.row) { flex-direction: row; gap: calc(26px * var(--k)); }
.t-moon.landscape:not(.row) .disc { flex: none; height: min(100%, calc(210px * var(--k))); }
.t-moon.landscape:not(.row) .txt { text-align: left; }
.t-moon.row { flex-direction: row; justify-content: flex-start; gap: 16px; padding: 12px 24px 12px 14px; }
.t-moon.row .disc { height: 100%; }
.t-moon.row .txt { text-align: left; }
.t-moon.row.roomy { justify-content: center; gap: 22px; }
.t-moon.row .nm { font-size: 22px; }
.t-moon.row .nx { font-size: 17px; }
.t-moon.tiny .txt { display: none; }
.t-moon.tiny { justify-content: center; }
/* Two cells: the moon and its phase's name, on two lines if need be. */
.t-moon.row.narrow:not(.tiny) { gap: 12px; padding: 14px 16px 14px 14px; }
.t-moon.row.narrow:not(.tiny) .disc { height: 64px; flex: none; }
.t-moon.row.narrow:not(.tiny) .nm { font-size: 19px; line-height: 1.15; white-space: normal; }
.t-moon.row.narrow:not(.tiny) .nx { display: none; }
.t-moon.tiny.row.narrow .disc { height: 100%; }

/* ---------- Trash day ---------- */
.t-bins { display: flex; flex-direction: column; }
.t-bins:not(.row) ul { margin: auto 0; }
.t-bins svg { display: block; width: 100%; height: 100%; fill: none; stroke: currentColor; stroke-width: 2.8; stroke-linecap: round; stroke-linejoin: round; }
.t-bins .lead { display: none; }
.t-bins ul { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: calc(14px * var(--k)); }
.t-bins li { display: grid; grid-template-columns: auto minmax(0, 1fr) auto; align-items: center; gap: calc(12px * var(--k)); font-size: calc(26px * var(--k)); }
.t-bins li .ic { width: calc(40px * var(--k)); height: calc(40px * var(--k)); }
.t-bins li .nm { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* Two columns wide: each bin's day under its name, so the name keeps its room. */
.t-bins:not(.row):not(.broad) li { grid-template-columns: auto minmax(0, 1fr); grid-template-rows: auto auto; row-gap: 0; line-height: 1.15; }
.t-bins:not(.row):not(.broad) li .ic { grid-row: 1 / span 2; }
.t-bins:not(.row):not(.broad) li b { grid-column: 2; grid-row: 2; font-size: .85em; }
.t-bins li b { font-weight: 700; white-space: nowrap; }
.t-bins li:not(.due) { opacity: .72; }
/* The day before and on the day: a ring round the tile, so it reads from across the room. */
.t-bins.due { box-shadow: inset 0 0 0 calc(5px * var(--k)) currentColor, var(--tile-shadow); }
.t-bins.row { flex-direction: row; align-items: center; gap: 18px; }
.t-bins.row .lbl, .t-bins.narrow .lbl { display: none; }
.t-bins.row ul { flex-direction: row; gap: 26px; }
.t-bins.row { justify-content: center; }
.t-bins.row li { font-size: 24px; }
.t-bins.row li .ic { width: 36px; height: 36px; }
.t-bins.row.narrow ul li:not(:first-child), .t-bins.row[data-w="3"] ul li:not(:first-child) { display: none; }
.t-bins.tiny.row.narrow ul { display: none; }
.t-bins.tiny.row.narrow .lead { display: flex; flex-direction: column; align-items: center; gap: 1px; }
.t-bins.tiny.row.narrow .lead .ic { width: 36px; height: 36px; }
.t-bins.tiny.row.narrow .lead .when { font-size: 14px; }
.t-bins.tiny.row.narrow .lead .nm { font-size: 11px; opacity: .75; max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.t-bins.tiny.due { box-shadow: inset 0 0 0 3px currentColor, var(--tile-shadow); }

/* ---------- Who's home ---------- */
.t-status ul { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: calc(9px * var(--k)); }
.t-status li { display: grid; grid-template-columns: auto minmax(0, 1fr) auto; align-items: center; gap: calc(12px * var(--k)); font-size: calc(24px * var(--k)); cursor: pointer; -webkit-tap-highlight-color: transparent; }
#app.readonly .t-status li { cursor: default; }
.t-status .av { width: calc(44px * var(--k)); height: calc(44px * var(--k)); border-radius: 50%; display: grid; place-items: center; font-size: calc(19px * var(--k)); font-weight: 700; transition: background-color .3s, color .3s, box-shadow .3s; }
.t-status li.home .av { background: #4f9a62; color: #fff; }
.t-status li.away .av { box-shadow: inset 0 0 0 2px currentColor; opacity: .5; }
.t-status .nm { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-weight: 600; }
.t-status li.away .nm { opacity: .6; }
.t-status .st { font-size: calc(16px * var(--k)); opacity: .7; }
.t-status li.none { display: block; cursor: default; font-size: calc(18px * var(--k)); opacity: .6; }
.t-status.broad:not(.row) ul, .t-status.roomy:not(.row) ul { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); column-gap: calc(22px * var(--k)); row-gap: calc(14px * var(--k)); }
.t-status.broad:not(.row) li, .t-status.roomy:not(.row) li { grid-template-columns: auto minmax(0, 1fr); grid-template-rows: auto auto; row-gap: 0; line-height: 1.15; }
.t-status.broad:not(.row) .av, .t-status.roomy:not(.row) .av { grid-row: 1 / span 2; }
.t-status.broad:not(.row) .st, .t-status.roomy:not(.row) .st { grid-column: 2; grid-row: 2; }
.t-status.row ul { flex-direction: row; gap: 18px; }
.t-status.row { justify-content: center; }
.t-status:not(.row) { display: flex; flex-direction: column; justify-content: center; }
.t-status.row li { grid-template-columns: auto auto; font-size: 22px; }
.t-status.row.roomy .av { width: 46px; height: 46px; font-size: 20px; }
.t-status.row .st { display: none; }
.t-status.row.narrow .nm, .t-status.row[data-w="3"] .nm { display: none; }
.t-status.tiny.row.narrow ul { display: grid; grid-template-columns: repeat(2, 1fr); gap: 6px; place-items: center; }
.t-status.tiny.row.narrow li { display: block; }
.t-status.tiny.row.narrow li:nth-child(n+5), .t-status.tiny.row.narrow .nm, .t-status.tiny.row.narrow .st { display: none; }
.t-status.tiny.row.narrow .av { width: 32px; height: 32px; font-size: 15px; }
.t-status.tiny.row.narrow li:only-child .av { width: 52px; height: 52px; font-size: 22px; }
.t-status.tiny.row.narrow ul:has(li:only-child) { grid-template-columns: 1fr; }

/* Trash day's options in the editor: each bin's name and remove button on one line, then its weekday
   and how often. */
#editor .bin + .bin { margin-top: 12px; padding-top: 12px; border-top: 1px solid #3f372f; }
#editor .bin .row { flex-wrap: nowrap; margin-top: 6px; }
#editor .bin input[data-bin-name] { flex: 1; width: auto; min-width: 0; }
#editor .bin .days button { flex: 1; min-width: 0; padding: 6px 0; }
#editor .bin .row button[data-bin-every] { flex: 1; }

/* ---------- Settings → Displays → Show numbers: this screen's number, over everything ---------- */
#identify { position: fixed; inset: 0; z-index: 220; display: grid; place-items: center; background: rgba(0, 0, 0, .5); pointer-events: none; }
#identify[hidden] { display: none; }
#identify .plate {
  transform: rotate(var(--turn, 0deg)); min-width: 44vmin; padding: 4vmin 7vmin 5vmin; border-radius: 6vmin; text-align: center;
  background: #f6efe4; color: #2b231d; box-shadow: 0 2vmin 8vmin rgba(0, 0, 0, .5);
  font-family: Inter, system-ui, -apple-system, "Segoe UI", Roboto, "Noto Sans", "DejaVu Sans", sans-serif;
}
#identify .n { font-size: 34vmin; font-weight: 700; line-height: 1; font-variant-numeric: tabular-nums; }
#identify .name { max-width: 70vmin; margin-top: 1.5vmin; font-size: 5vmin; font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
#identify .how { margin-top: 1.2vmin; font-size: 2.6vmin; opacity: .65; }
