/* The calendar as it is drawn -- everything both the wall and the pocket
   need. Neither page has a <style> of its own for anything in here. */

/* ---------------------------------------------------------------------------
   A wall display for a monitor standing on its short edge: 1080 across, 1920
   down. Nothing scrolls, nothing is clicked, and every size is a multiple of
   the viewport height, so the same file fills a different panel without being
   redesigned.

   The picture behind it is the reason for the glass. Panels are translucent and
   blurred so the photograph is still there — but only the three big panels are
   blurred, never the thirty-five day squares: a backdrop-filter per square is
   what turns a Pi into a slideshow.
   --------------------------------------------------------------------------- */
:root {
  --u: 1vh;

  /* ---- day ---- */
  --ink:        #1f232b;
  --ink-dim:    #4e596a;
  --ink-faint:  #798393;
  --today:      #b5793a;
  --house:      #566575;
  --page:       #efeae1;
  --lift:       0 calc(var(--u) * .14) calc(var(--u) * .42) rgba(60, 45, 25, .14),
                0 calc(var(--u) * .8)  calc(var(--u) * 2.1) rgba(60, 45, 25, .10);

  /* Opaque enough that ink stays ink over a dark photograph, sheer enough that
     the photograph is still the thing behind it. */
  --glass:      rgba(255, 252, 245, .38);
  --glass-2:    rgba(255, 255, 252, .24);
  --glass-edge: rgba(255, 255, 248, .60);
  --glass-line: rgba(70, 70, 80, .12);
  --shadow:     0 calc(var(--u) * .9) calc(var(--u) * 2.6) rgba(40, 35, 25, .12);
  --today-soft: rgba(255, 236, 208, .72);
  /* The editing sheet is the one surface that is not glass: it sits over the
     whole wall and has to be read at arm's length, so it is opaque. */
  --sheet:      #f7f4ee;
  --card:       #f7f4ee;

  /* Ten colors a room can live with. Not loud — this hangs on a wall all day —
     but with enough chroma to survive being a 7 px stripe or a 20% tint behind
     a chip, and far enough apart in hue AND lightness that they stay apart for
     a color-blind reader. */
  --blue:   #2f74d8;
  --green:  #14a05f;
  --amber:  #e0a017;
  --red:    #dc4d43;
  --purple: #7b55e6;
  --teal:   #039fb2;
  --pink:   #dc4f92;
  --lime:   #78b117;
  --orange: #e57a22;
  --gray:   #7f8a9c;
}
body[data-theme="night"] {
  --ink:        #f7fafd;
  --ink-dim:    #ccd6e2;
  --ink-faint:  #9dabbc;
  --today:      #f0b877;
  --house:      #9fb2c6;
  --page:       #0b0d12;
  --lift:       0 calc(var(--u) * .14) calc(var(--u) * .42) rgba(0, 0, 0, .50),
                0 calc(var(--u) * .8)  calc(var(--u) * 2.1) rgba(0, 0, 0, .38);

  /* Smoked, not black: a slate-gray panel with light on it, rather than a hole
     cut in the screen. Dark enough to read light text against a bright
     photograph, light enough that a room does not feel switched off. */
  --glass:      rgba(38, 45, 57, .32);
  --glass-2:    rgba(255, 255, 255, .08);
  --glass-edge: rgba(255, 255, 255, .14);
  --glass-line: rgba(255, 255, 255, .10);
  --shadow:     0 calc(var(--u) * .9) calc(var(--u) * 2.6) rgba(0, 0, 0, .35);
  --today-soft: rgba(224, 167, 101, .18);
  --sheet:      #1c222c;
  --card:       #313a49;
  --today-track: rgba(255, 255, 255, .07);

  --blue:   #5fb0ff;
  --green:  #2fd696;
  --amber:  #ffc542;
  --red:    #ff7a6e;
  --purple: #b184ff;
  --teal:   #29d3e2;
  --pink:   #ff7ec0;
  --lime:   #a8e142;
  --orange: #ff9c47;
  --gray:   #96a3b8;
}

* { box-sizing: border-box; margin: 0; padding: 0; }
html, body {
  height: 100%; width: 100%; overflow: hidden;
  color: var(--ink);
  font-family: -apple-system, "Segoe UI", Roboto, "Helvetica Neue", "DejaVu Sans", sans-serif;
  font-variant-numeric: tabular-nums;
  -webkit-font-smoothing: antialiased;
  cursor: none;                        /* there is no mouse on a wall */
}
/* The base color lives on the root element, where it is painted before
   everything else; body stays transparent so #bg is what you see. */
html { background: #efeae1; }
html:has(body[data-theme="night"]) { background: #0b0d12; }
body.has-cursor { cursor: default; }

/* ------------------------------ the wall ------------------------------ */
/* Stacked with positive z-indexes, not negative ones. A negative z-index layer
   is painted BEFORE the body's own background, so the photograph would sit
   behind the page's color and never be seen — an hour of "the image is loading
   fine and is not on screen". */
#bg, #scrim { position: fixed; inset: 0; z-index: 0; }
#bg {
  background-size: cover; background-position: center; background-repeat: no-repeat;
  transition: opacity 1.2s ease;
}
/* ---- paper: a printed sheet, for a monitor in a wooden frame -----------
   Every other background is a WALL with glass panels floating in front of it.
   This one is not a wall — it is the calendar itself, so the panels have to
   stop being panels. See the print rules further down: no blur, no float, no
   rounded corners, hairline rules instead of gaps. Two noise layers do the
   sheet: fine fibre multiplied in, and a slow cloudiness that keeps a large
   flat area from looking like a flat area. */
body[data-bg="paper"] #bg {
  background-color: #f3ecdc;
  background-image:
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='180' height='180'%3E%3Cfilter id='f'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='4' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3CfeComponentTransfer%3E%3CfeFuncA type='linear' slope='0.32'/%3E%3C/feComponentTransfer%3E%3C/filter%3E%3Crect width='180' height='180' filter='url(%23f)'/%3E%3C/svg%3E"),
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='700' height='700'%3E%3Cfilter id='c'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.008' numOctaves='5' seed='4' stitchTiles='stitch' result='n'/%3E%3CfeDiffuseLighting in='n' lighting-color='%23fffdf6' surfaceScale='1.1' diffuseConstant='1.05'%3E%3CfeDistantLight azimuth='120' elevation='62'/%3E%3C/feDiffuseLighting%3E%3C/filter%3E%3Crect width='700' height='700' filter='url(%23c)'/%3E%3C/svg%3E"),
    /* A sheet lit from above sits a shade darker at its edges. Without this the
       paper reads as a color rather than as a thing with edges — which matters
       more, not less, once there is a wooden frame around it. */
    radial-gradient(150vh 120vh at 50% 26%, #fefbf2 0%, rgba(254,251,242,0) 72%),
    linear-gradient(168deg, #f6f0e2 0%, #e7dcc6 100%);
  background-size: 180px 180px, 700px 700px, cover, cover;
  background-repeat: repeat, repeat, no-repeat, no-repeat;
  background-blend-mode: multiply, soft-light, normal, normal;
}
body[data-theme="night"][data-bg="paper"] #bg {
  background-color: #17150f;
  background-image:
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='180' height='180'%3E%3Cfilter id='f'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='4' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3CfeComponentTransfer%3E%3CfeFuncA type='linear' slope='0.22'/%3E%3C/feComponentTransfer%3E%3C/filter%3E%3Crect width='180' height='180' filter='url(%23f)'/%3E%3C/svg%3E"),
    radial-gradient(150vh 120vh at 50% 26%, #241f16 0%, rgba(36,31,22,0) 70%),
    linear-gradient(168deg, #16140e 0%, #1e1a12 100%);
  background-size: 180px 180px, cover, cover;
  background-repeat: repeat, no-repeat, no-repeat;
  background-blend-mode: soft-light, normal, normal;
}

/* ---- slate: dark stone. The panels stop being paper and start glowing. ---- */
body[data-bg="slate"] #bg {
  background-color: #23262b;
  background-image:
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='240' height='240'%3E%3Cfilter id='g'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.7' numOctaves='3' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3CfeComponentTransfer%3E%3CfeFuncA type='linear' slope='0.5'/%3E%3C/feComponentTransfer%3E%3C/filter%3E%3Crect width='240' height='240' filter='url(%23g)'/%3E%3C/svg%3E"), url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='620' height='620'%3E%3Cfilter id='p'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.03' numOctaves='6' seed='9' stitchTiles='stitch' result='n'/%3E%3CfeDiffuseLighting in='n' lighting-color='%23ffffff' surfaceScale='3.2' diffuseConstant='1.15'%3E%3CfeDistantLight azimuth='128' elevation='52'/%3E%3C/feDiffuseLighting%3E%3C/filter%3E%3Crect width='620' height='620' filter='url(%23p)'/%3E%3C/svg%3E"),
    radial-gradient(130vh 100vh at 20% -10%, #3b414a 0%, rgba(59,65,74,0) 65%),
    linear-gradient(168deg, #1f2329 0%, #2b3037 100%);
  background-size: 240px 240px, 620px 620px, cover, cover;
  background-repeat: repeat, repeat, no-repeat, no-repeat;
  background-blend-mode: soft-light, multiply, normal, normal;
}

/* Enough veil that white text-on-glass is readable over any photograph, and no
   more: past this the picture may as well not be there. */
#scrim { z-index: 1; }
/* A thin veil, not a curtain: enough to keep dark ink legible where a
   photograph goes bright, and little enough that the photograph is still the
   photograph. */
body.has-photo #scrim {
  background:
    linear-gradient(180deg, rgba(250,247,242,.20) 0%, rgba(250,247,242,.08) 45%, rgba(250,247,242,.22) 100%);
}
body[data-theme="night"].has-photo #scrim {
  background:
    linear-gradient(180deg, rgba(6,8,12,.16) 0%, rgba(6,8,12,.05) 45%, rgba(6,8,12,.20) 100%);
}

/* Over a photograph the panels thin out and lean harder on the blur. The
   picture — and its color — carries on through the glass instead of stopping
   at it. */
/* Thin glass gives the quiet text less to sit on, so the quiet text stops being
   quite so quiet — and which way "quieter" goes depends entirely on whether the
   glass is pale or smoked. */
/* ---- map colors -------------------------------------------------------
   The other palette is screen color: saturated, lit from behind, made to
   carry at four metres. This one is print color, off a survey sheet -- ochre,
   forest, terracotta, heather -- and it is quieter without going muddy.
   The first six are the ones that matter: a household rarely has ten people,
   and blue / forest / ochre / terracotta / heather / wetland are as far apart
   in hue AND in lightness as six inks get, so they stay apart for a
   color-blind reader and in a photograph of the wall. */
body[data-palette="map"] {
  --blue:   #3a6ea5;
  --green:  #4f7942;
  --amber:  #c8952b;
  --red:    #b04a3f;
  --purple: #6b5b95;
  --teal:   #2f8a86;
  --pink:   #b5638a;
  --lime:   #8a9a3f;
  --orange: #cf7c3a;
  --gray:   #6f7a80;
}
/* On smoked glass the same inks would sink into the panel, so they are lifted
   and desaturated a shade -- the same six hues, printed on dark paper. */
body[data-theme="night"][data-palette="map"] {
  --blue:   #7fa9d8;
  --green:  #8fbf7a;
  --amber:  #e6bd68;
  --red:    #e08b7f;
  --purple: #a99ad4;
  --teal:   #6fc6c1;
  --pink:   #dd94b6;
  --lime:   #bcc978;
  --orange: #eaa871;
  --gray:   #a3aeb5;
}

body:not([data-theme="night"]).has-photo {
  --glass:      rgba(255, 252, 245, .24);
  --glass-2:    rgba(255, 255, 252, .14);
  --glass-edge: rgba(255, 255, 250, .46);
  --ink-dim:    #47505f;
  --ink-faint:  #6e7887;
}
/* Smoked glass: dark enough to be a panel in its own right, sheer enough that
   the photograph goes on behind it. */
body[data-theme="night"].has-photo {
  --glass:      rgba(34, 41, 53, .26);
  --glass-2:    rgba(255, 255, 255, .09);
  --glass-edge: rgba(255, 255, 255, .18);
  --ink:        #fbfdff;
  --ink-dim:    #d6dfea;
  --ink-faint:  #a9b5c4;
}
/* On dark glass a faded row disappears rather than receding. */
body[data-theme="night"] .ev.past { opacity: .55; }
body[data-theme="night"] .day.past { opacity: .62; }
/* Pale glass over a DARK wall is the one combination thin panes punish: the
   wall darkens the pane, and the quiet grays — the quote, the section labels,
   the weekday row — go with it. Slate gets a slightly denser pane, and the
   faint ink is a shade darker everywhere to match the thinner glass. */
body[data-bg="slate"]:not([data-theme="night"]) {
  --glass:      rgba(255, 252, 245, .48);
  --glass-2:    rgba(255, 255, 252, .34);
  --ink-faint:  #545d6b;
}

body.has-photo .glass {
  backdrop-filter: blur(calc(var(--u) * 4.8)) saturate(165%);
  -webkit-backdrop-filter: blur(calc(var(--u) * 4.8)) saturate(165%);
}
/* At this thickness the pane is barely paint at all, so the type gets a hairline
   of its own background to sit on. Invisible over a plain wall; the difference
   between readable and not where a photograph goes light behind dark text. */
body.has-photo #app { text-shadow: 0 1px 3px rgba(255, 255, 255, .45); }
body[data-theme="night"].has-photo #app { text-shadow: 0 1px 3px rgba(0, 0, 0, .55); }
/* A veil mixes the picture toward a flat gray, which costs it color as well as
   light — so the color is put back before the veil takes it, and then some.
   Contrast comes up a touch with it: saturation alone on a hazy photograph
   makes it vivid and still flat. */
body.has-photo #bg { filter: saturate(1.5) contrast(1.06); }
body[data-theme="night"].has-photo #bg { filter: saturate(1.55) contrast(1.1); }

#app {
  position: relative; z-index: 2;
  height: 100%; width: 100%;
  display: flex; flex-direction: column;
  padding: calc(var(--u) * 1.3);
  gap: calc(var(--u) * .9);
  transform: translate(var(--shift-x, 0px), var(--shift-y, 0px));
}

/* The masthead and today, in one box -- but `display: contents` means the box
   is not there: both go on being #app's own flex children, and the wall is
   laid out to the pixel as it was before this element existed. It becomes a
   real element only on a phone, where it is the thing that stays put. */
#top { display: contents; }

.glass {
  background: var(--glass);
  border: 1px solid var(--glass-edge);
  border-radius: calc(var(--u) * 2);
  box-shadow: var(--shadow);
  /* Three of these on the page, and no more. */
  /* Thinner panes lean harder on the blur: it is the blur, not the paint, that
     keeps a line of text off a busy background. */
  backdrop-filter: blur(calc(var(--u) * 4)) saturate(140%);
  -webkit-backdrop-filter: blur(calc(var(--u) * 4)) saturate(140%);
}

/* ------------------------------- header ------------------------------- */
header {
  display: flex; flex-direction: column; gap: calc(var(--u) * .8);
  flex: 0 0 auto;
  padding: calc(var(--u) * 1.5) calc(var(--u) * 2.4);
}
.head-row { display: flex; align-items: center; justify-content: space-between; gap: calc(var(--u) * 2); }
.dow {
  font-size: calc(var(--u) * 5); line-height: 1;
  font-weight: 800; letter-spacing: -.015em; text-transform: uppercase;
}
.dm { font-size: calc(var(--u) * 2.6); line-height: 1.35; color: var(--ink-dim); font-weight: 600; }
.headline {
  font-size: calc(var(--u) * 1.8); color: var(--ink-faint); font-weight: 700;
  letter-spacing: .06em; text-transform: uppercase; margin-top: calc(var(--u) * .3);
}
/* The clock's two sizes are named, because the AM above it is positioned FROM
   them. Four different rules set a clock size -- the wall, paper, a landscape
   laptop and a phone -- and there were only ever two hand-tuned offsets to go
   with them, so AM sat right in the hall and floated a full unit high in your
   hand. Anything that changes the size now changes only these. */
.clock {
  --clock-fs: calc(var(--u) * 6);
  --ap-fs:    calc(var(--u) * 1.5);
  font-size: var(--clock-fs);
  line-height: .95; font-weight: 250; letter-spacing: -.03em; text-align: right;
}
/* Both halves of the day, with the one you are not in barely there. A single
   "PM" is a label you read; a pair with one of them lit is a position -- you
   see which half of the day it is before you have read anything, which is the
   only thing the suffix was ever for.
   PM keeps the place the old single suffix had, sitting on the digits' own
   baseline, and AM is lifted out of the flow to hang above it with its top
   against the top of the numerals. Stacking them in a flex column instead put
   the BOX on the baseline and pushed PM down a whole line. */
.clock small.ampm {
  position: relative; display: inline-block; vertical-align: baseline;
  font-size: var(--ap-fs); font-weight: 600; letter-spacing: .04em;
  line-height: 1.02; margin-left: calc(var(--u) * .5);
}
.clock small.ampm i { font-style: normal; display: block;
                      color: var(--ink-faint); opacity: .26; }
.clock small.ampm i.on { color: var(--ink-dim); opacity: 1; }
/* The top of AM against the top of the numerals, worked out rather than
   guessed. The .ampm box sits on the clock's baseline, so measuring up from
   its own bottom edge:

     numerals reach   0.72 x clock-size   above the baseline (cap height)
     this box's floor 0.22 x ap-size      below it (descent, at line-height 1.02)
     the AM element   1.02 x ap-size      tall

   which leaves bottom = 0.72*clock - 0.80*ap. At the wall's 6u and 1.5u that
   is 3.12u, and the number tuned by eye for the wall was 3.1 -- so the model
   is the one that was already being approximated, and now every other size
   gets it too instead of inheriting the hall's. */
.clock small.ampm i.am {
  position: absolute; left: 0;
  bottom: calc(var(--clock-fs) * 0.72 - var(--ap-fs) * 0.8);
}

/* -------------------------------- today ------------------------------- */
.today-panel {
  padding: calc(var(--u) * 1.3) calc(var(--u) * 1.9) calc(var(--u) * 1.1);
  display: flex; flex-direction: column; gap: calc(var(--u) * .8);
  flex: 0 0 auto;
  /* Today takes the room today needs; the grid below fits itself into what is
     left. The cap only exists so an absurd day still leaves a week visible. */
  max-height: 56%;
  overflow: hidden;
}
#todayList { flex: 1 1 auto; min-height: 0; overflow: hidden; }
.today-panel h2, .tomorrow { flex: 0 0 auto; }
.today-panel h2 {
  font-size: calc(var(--u) * 1.6); font-weight: 800; letter-spacing: .22em;
  text-transform: uppercase; color: var(--ink-faint);
  display: flex; justify-content: space-between; align-items: baseline;
}
.today-panel h2 .count { letter-spacing: .04em; color: var(--ink-dim); }

.ev {
  /* time · color · name · pill. The color column is a fixed width, which is
     the whole point: it is what every name lines up against. */
  /* The time column is a floor, not a fixed width: with no band above it the
     list says "9:00 AM-5:00 PM" instead of "9:00 AM", and at a fixed 12.5u that
     printed straight over the title beside it. max-content lets it take what a
     range needs and no more, and the name still lines up against the color. */
  display: grid;
  grid-template-columns: minmax(calc(var(--u) * 12.5), max-content)
                         calc(var(--u) * .7) minmax(0, 1fr) auto;
  align-items: center; gap: calc(var(--u) * 1.2);
  padding: calc(var(--u) * .7) 0;
  border-top: 1px solid var(--glass-line);
}
.ev:first-of-type { border-top: 0; }
.ev .when  { font-size: calc(var(--u) * 2); font-weight: 700; white-space: nowrap; }
/* Two lines rather than an ellipsis: "Pick up Lizuca from piano" cut to "Pick
   up Lizuca fr…" is the one entry on the panel you cannot read, and it is
   always the one with the detail in it. */
.ev .what  {
  font-size: calc(var(--u) * 2.3); font-weight: 500; line-height: 1.18;
  /* Wrapped, not cut. An entry called "Pick up Lizuca from piano and drop her
     at swimming" is that long because every word of it is the point; a clamp
     at two lines would lose the half that says where she is going. If a day of
     these overflows the panel, trimToFit() drops whole entries and counts
     them — which is honest — rather than shortening every one of them. */
  white-space: normal; overflow-wrap: anywhere;
}
/* The place sits under the name rather than beside it, so the name has the whole
   column to wrap into and is not competing with "Music school" for it. */
.ev .where {
  display: block; font-size: calc(var(--u) * 1.5); color: var(--ink-faint);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  margin-top: calc(var(--u) * .15);
}
.ev .whatwrap { min-width: 0; }
.ev .in {
  font-size: calc(var(--u) * 1.55); white-space: nowrap; font-weight: 700;
  color: var(--ink-dim); background: var(--glass-2);
  border: 1px solid var(--glass-edge); border-radius: 999px;
  padding: calc(var(--u) * .3) calc(var(--u) * .9);
}
/* Today's list, read from across the room: what is on now is bold, what is next
   is bigger than anything else on the panel, what is still to come is plain,
   and what has been is small and out of the way. Size carries the ordering as
   much as position does. */
/* Thinner glass makes a faded row fade twice, so past entries recede a little
   less than they used to. */
/* What has already happened is kept, not shown: small enough to be scenery,
   large enough to answer "did I miss it?" — and it gives its space back to the
   month, which is a better use of it. */
.ev.past { opacity: .55; padding: calc(var(--u) * .38) 0; }
.ev.past  .when  { font-size: calc(var(--u) * 1.35); font-weight: 500; }
.ev.past  .what  { font-size: calc(var(--u) * 1.5); font-weight: 400; }
.ev.past  .where { font-size: calc(var(--u) * 1.15); }
.ev.past  .bar   { min-height: calc(var(--u) * 1.5); }

.ev.now   .when { font-weight: 800; }
.ev.now   .what { font-size: calc(var(--u) * 2.3); font-weight: 700; }

.ev.next  .when { font-size: calc(var(--u) * 2.2); font-weight: 800; }
.ev.next  .what { font-size: calc(var(--u) * 2.9); font-weight: 600; letter-spacing: -.01em; }

.ev.later .what { font-size: calc(var(--u) * 2.2); font-weight: 500; }

/* "now" reads as a state, "in 25 min" as a countdown; both are the same pill. */
.ev .in.happening { color: var(--ink); border-color: var(--today); font-weight: 800; }
/* Asked for out loud. The panel keeps its place — there is no room on a wall
   for a dialog, and nothing to dismiss it with — but says plainly that it is
   not showing today, and how long until it is again. */
.today-panel.asked { border-color: var(--asked, var(--today)); box-shadow: var(--shadow), inset 0 0 0 1px var(--asked, var(--today)); }
.today-panel.asked h2 { color: var(--asked, var(--today)); }
.today-panel h2 .back {
  font-size: calc(var(--u) * 1.4); letter-spacing: .04em; text-transform: none;
  font-weight: 600; color: var(--ink-faint); margin-left: calc(var(--u) * 1);
}
.day.asked { box-shadow: inset 0 0 0 calc(var(--u) * .18) var(--asked, var(--today)); border-color: var(--asked, var(--today)); }

.today-panel .empty { font-size: calc(var(--u) * 2.3); color: var(--ink-faint); padding: calc(var(--u) * 1.2) 0; }

/* Whose it is, as a stripe between the time and the name.
   A badge with an initial in it is a different width on every row, so every
   name started somewhere else; a stripe is always the same width and the names
   line up hard against it. Two or three people split it. The legend above the
   month is what says which color is whom. */
.ev .bar {
  align-self: stretch; min-height: calc(var(--u) * 2.6);
  border-radius: 999px; background: var(--c, var(--gray));
}
.ev .bar.house {
  background: repeating-linear-gradient(180deg,
              var(--glass-line) 0 calc(var(--u) * .35),
              transparent calc(var(--u) * .35) calc(var(--u) * .8));
}

.tomorrow {
  border-top: 1px solid var(--glass-line); padding-top: calc(var(--u) * .8);
  font-size: calc(var(--u) * 1.6); color: var(--ink-dim);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.tomorrow b { color: var(--ink-faint); font-weight: 800; letter-spacing: .18em; text-transform: uppercase; margin-right: .6em; }

/* -------------------------------- month ------------------------------- */
.grid {
  flex: 1 1 auto; display: flex; flex-direction: column; min-height: 0;
  gap: calc(var(--u) * .45);
  padding: calc(var(--u) * .9);
}
.monthline {
  display: flex; align-items: baseline; justify-content: space-between;
  gap: calc(var(--u) * .6) calc(var(--u) * 1.2); flex: 0 0 auto; flex-wrap: wrap;
  padding: 0 calc(var(--u) * .6);
}
.monthline .m { font-size: calc(var(--u) * 2); font-weight: 800; letter-spacing: .03em; text-transform: uppercase; }
.monthline .r { font-size: calc(var(--u) * 1.5); color: var(--ink-faint); font-weight: 700; letter-spacing: .1em; text-transform: uppercase; }

/* A key, on a line of its own under the month: read once, then ignored, which
   is why it does not belong on the same line as the month's name.
   Each name is a pill in that person's color — the same shape and the same
   tint as the entries in the squares above it, so the key looks like the thing
   it is explaining rather than like a footnote about it. */
.legend {
  display: flex; flex-wrap: wrap; justify-content: center;
  gap: calc(var(--u) * .35) calc(var(--u) * .6);
  align-items: center; flex: 0 0 auto;
  font-size: calc(var(--u) * 1.2); font-weight: 600;
  border-top: 1px solid var(--glass-line);
  padding-top: calc(var(--u) * .5);
}
.legend[hidden] { display: none; }
.legend span {
  display: inline-flex; align-items: center;
  padding: calc(var(--u) * .18) calc(var(--u) * .9);
  border-radius: 999px; color: var(--ink);
  background: color-mix(in srgb, var(--c, var(--gray)) 46%, transparent);
}

.weekdays {
  display: grid; grid-template-columns: repeat(7, 1fr); gap: calc(var(--u) * .5);
  font-size: calc(var(--u) * 1.15); letter-spacing: .14em; text-transform: uppercase;
  color: var(--ink-faint); font-weight: 800; text-align: center; flex: 0 0 auto;
}
.weeks { flex: 1 1 auto; display: grid; gap: calc(var(--u) * .5); min-height: 0; }
.week { display: grid; grid-template-columns: repeat(7, 1fr); gap: calc(var(--u) * .5); min-height: 0; }

.day {
  background: var(--glass-2);
  border: 1px solid var(--glass-line);
  border-radius: calc(var(--u) * .9);
  padding: calc(var(--u) * .45) calc(var(--u) * .45) calc(var(--u) * .35);
  display: flex; flex-direction: column; gap: calc(var(--u) * .2);
  min-width: 0; overflow: hidden;
}
.day .n {
  display: flex; align-items: baseline; justify-content: space-between; gap: .4em;
  /* A smaller date leaves room for another entry under it, which is what the
     square is for. */
  font-size: calc(var(--u) * 1.55); font-weight: 700; line-height: 1;
}
/* Chips keep their height rather than squashing: a squashed chip is a line of
   text with its top and bottom shaved off, and an overflowing one is something
   trimToFit() can turn into a "+2". */
.day .n, .day .chip { flex: 0 0 auto; }
.day .plus { font-size: calc(var(--u) * 1.15); color: var(--ink-faint); font-weight: 700; }
.day.weekend { background: var(--glass-2); opacity: .92; }
.day.weekend .n { color: var(--ink-dim); }
.day.today {
  background: var(--today-soft);
  border-color: var(--today);
  box-shadow: inset 0 0 0 calc(var(--u) * .18) var(--today);
}
.day.today .n { color: var(--today); font-weight: 900; }
.day.past { opacity: .5; }

.chip {
  display: flex; align-items: baseline; gap: calc(var(--u) * .4);
  font-size: calc(var(--u) * 1.15); line-height: 1.22;
  white-space: nowrap; overflow: hidden;
  border-radius: calc(var(--u) * .4);
  padding: calc(var(--u) * .12) calc(var(--u) * .4);
  /* A tint, not the color itself: the square has to stay readable text on a
     pale panel. Strong enough now that whose day it is reads at a glance. */
  background: color-mix(in srgb, var(--c, var(--blue)) 34%, transparent);
}
.chip .s { overflow: hidden; text-overflow: ellipsis; }
.chip.all { background: color-mix(in srgb, var(--c, var(--blue)) 58%, transparent); font-weight: 600; }

/* A tint mixed with transparent takes on whatever is behind it, and behind a
   smoked pane that is something dark — the same 34% that reads as a color on
   pale glass reads as a shade on dark. So smoked panels take far more of it.
   Past about 60% the chip stops being a tint and becomes the color itself,
   which means the text on it has to flip: the night palette is bright by
   design, and white on a bright lime is unreadable. Dark ink from here up. */
body[data-theme="night"] .chip {
  background: color-mix(in srgb, var(--c, var(--blue)) 78%, transparent);
  color: #12161d;
}
body[data-theme="night"] .chip .t { color: rgba(0, 0, 0, .62); }
body[data-theme="night"] .chip.all {
  background: color-mix(in srgb, var(--c, var(--blue)) 92%, transparent);
  color: #12161d; font-weight: 700;
}
body[data-theme="night"] .legend span {
  background: color-mix(in srgb, var(--c, var(--gray)) 88%, transparent);
  color: #12161d; font-weight: 700;
}

/* -------------------------------- strip ------------------------------- */
/* The bottom of the screen: a line worth reading, and where the photograph came
   from. Not a status bar — there is nothing here about the app itself. */
.strip {
  flex: 0 0 auto; display: flex; align-items: center; justify-content: space-between;
  gap: calc(var(--u) * 2);
  padding: calc(var(--u) * .9) calc(var(--u) * 1.8);
}

/* ------------------------------ the coast ------------------------------
   Under the month: what the sea is doing, when the light goes, what it is
   like outside. Three cells, all the same shape — a label, an answer, and
   the small print — because they are three answers to the same kind of
   question and reading them should not need three different habits. */
.coast {
  flex: 0 0 auto;
  /* Flex, not a three-column grid: a cell only appears when it has something
     to say, and a grid keeps holding the empty column open for one that never
     came -- which is how "7:09a - 7:23p" ended up as "7:09a - 7..." on a wall
     with no forecast yet. Here the cells that exist take the whole width. */
  display: flex; align-items: stretch;
  gap: calc(var(--u) * 1.6);
  padding: calc(var(--u) * 1) calc(var(--u) * 1.8);
}
.coast[hidden] { display: none; }
/* Bottom-aligned, not centered: the kayak cell carries a chart above its label
   and the other two do not, and three labels at three heights read as three
   unrelated things rather than one row. */
.coast > div { flex: 1 1 0; min-width: 0;
               display: flex; flex-direction: column; justify-content: flex-start;
               gap: calc(var(--u) * .15); }
/* The recommendation is a sentence and the other two are numbers, so it gets
   the room a sentence needs.
   Written as `.coast > .x` and not `.x`: a bare class loses to `.coast > div`,
   which has a type selector in it and therefore more specificity -- so every
   share I set here was quietly ignored and all three cells stayed equal. */
.coast > .c-kayak { flex: 1.15 1 0; }
.coast > .c-sun   { flex: 1 1 0; }
/* Every cell opens with its picture, and every picture is the same height, so
   the three labels underneath sit on one line across the row. */
.c-art { display: block; width: 100%; height: calc(var(--u) * 4.6); overflow: visible;
         margin-bottom: calc(var(--u) * 1.1); }
.coast > div + div { border-left: 1px solid var(--glass-line); padding-left: calc(var(--u) * 1.6); }
.c-kayak .c-v { margin-top: calc(var(--u) * .1); }
.c-h {
  font-size: calc(var(--u) * .95); font-weight: 700; letter-spacing: .1em;
  text-transform: uppercase; color: var(--ink-faint); white-space: nowrap;
}
.c-v {
  font-size: calc(var(--u) * 1.75); font-weight: 600; line-height: 1.15;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.c-s { font-size: calc(var(--u) * 1.15); color: var(--ink-dim); line-height: 1.3;
       white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.c-v.quiet { font-size: calc(var(--u) * 1.6); font-weight: 500; color: var(--ink-dim); }

/* The tide, drawn rather than tabulated: you read a curve for its shape, and
   the shape is the whole point — where the water is going, and when it turns.
   The shaded block is the paddle. */
.tidechart .sea { fill: var(--blue); opacity: .13; }
.tidechart .wave  { fill: none; stroke: var(--ink-faint); stroke-width: 1.5; opacity: .75; }
.tidechart .fill  { fill: var(--ink-faint); opacity: .10; }
.tidechart .win   { fill: var(--blue); opacity: .18; }
/* Get in, turn round, get back. The turn is the one the tide decides for you,
   so it is drawn as the stronger of the three. */
.tidechart .winl  { stroke: var(--blue); stroke-width: 1; opacity: .55; }
.tidechart .turnl { stroke: var(--blue); stroke-width: 1.4; opacity: .8;
                    stroke-dasharray: 2 2; }
.tidechart .mark  { fill: var(--ink-dim); font-size: 8px; font-weight: 600; }
.tidechart .nowl  { stroke: var(--today); stroke-width: 1.5; }

/* One line and one dot. */
/* No label over it and no text under it, so the arc takes the cell: the whole
   width, and the height the other cells spend on a heading and two lines. */
/* Both drawings get the same height and the same gap under them: the times at
   the foot of the arc and the river's name under the tide are a line apart
   from what they belong to, and half a line from what they do not. */
.c-sun { justify-content: center; }
.sunarc .path { fill: none; stroke: var(--ink-faint); stroke-width: 1.3; opacity: .6;
                stroke-dasharray: 2.5 3; }
.sunarc .sun  { fill: var(--today); }
.sunarc .end  { fill: var(--ink-dim); font-size: 9px; font-weight: 600; }
/* The arc is one thing and the three days are another; with no gap they read as
   one crowded block of weather. */
.c-sun .c-art { margin-bottom: calc(var(--u) * 2.2); }
body.week-grid .c-sun .c-art { margin-bottom: calc(var(--u) * 2.6); }

/* What it is doing out there, and which way it is blowing. */
.skyart .glyph  { fill: none; stroke: var(--ink-dim); stroke-width: 1.6;
                  stroke-linecap: round; stroke-linejoin: round; }
.skyart .disc   { fill: var(--today); stroke: none; }
.skyart .cloud  { fill: var(--ink-faint); opacity: .28; stroke: none; }
.skyart .drop   { stroke: var(--blue); stroke-width: 1.4; stroke-linecap: round; opacity: .7; }
/* Small. The three days are a strip of numbers with a picture each, and the
   picture is the label, not the point -- the temperatures are what you read.
   The marks on the ARC are the ones that had to grow. */
.skyart { display: block; width: 100%; height: calc(var(--u) * 2.4); }
body.week-grid .skyart { height: calc(var(--u) * 2.6); }

/* Today, tomorrow, and the day after: three narrow columns rather than one
   sentence, because what you want off a wall is the shape of the week -- is it
   getting better or worse -- and three pictures say that and a sentence does
   not. */
.c-sun .days { display: flex; gap: calc(var(--u) * .5); align-items: flex-end;
               margin-bottom: calc(var(--u) * .45); }
.c-sun .d { flex: 1 1 0; min-width: 0; text-align: center; }
.c-sun .dl { font-size: calc(var(--u) * 1.05); color: var(--ink-faint);
             letter-spacing: .04em; text-transform: uppercase; white-space: nowrap; }
.c-sun .d.now .dl { color: var(--ink-dim); font-weight: 700; }
.c-sun .dt { font-size: calc(var(--u) * 1.45); font-weight: 600; white-space: nowrap;
             font-variant-numeric: tabular-nums; }
.c-sun .d:not(.now) .dt { color: var(--ink-dim); font-weight: 500; }
.c-s.wind { display: flex; align-items: center; gap: calc(var(--u) * .5); }
.c-s.wind .skyart { flex: 0 0 auto; width: calc(var(--u) * 2.2); height: calc(var(--u) * 2.2); }
body[data-style="paper"] .coast > div + div { border-left-color: var(--rule); }
body[data-style="paper"] .tidechart .wave { stroke: var(--ink-faint); opacity: .9; }
/* The line worth reading sits with the date, at eye level. */
.quote {
  font-size: calc(var(--u) * 1.5); line-height: 1.35; color: var(--ink-dim); font-style: italic;
  border-top: 1px solid var(--glass-line); padding-top: calc(var(--u) * .7);
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
}
.quote b { font-style: normal; font-weight: 700; color: var(--ink-faint); }
.quote b::before { content: "— "; }

/* And one thing worth knowing, at the foot. */
.fact {
  font-size: calc(var(--u) * 1.6); line-height: 1.35; color: var(--ink-dim);
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
}
/* A drawn bulb rather than the words "did you know", and drawn rather than an
   emoji: a Pi without a color-emoji font would show a box, and this one is
   always the right color because it is the text color. */
.fact { display: flex; align-items: center; gap: calc(var(--u) * 1); }
.fact svg {
  flex: 0 0 auto; width: calc(var(--u) * 2.2); height: calc(var(--u) * 2.2);
  fill: none; stroke: var(--ink-faint); stroke-width: 1.6;
  stroke-linecap: round; stroke-linejoin: round;
}
.fact span { display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }


.trouble {
  flex: 0 0 auto; align-self: center; text-align: center;
  font-size: calc(var(--u) * 1.5); font-weight: 600; color: var(--ink-dim);
  background: var(--glass); border: 1px solid var(--glass-edge); border-radius: 999px;
  padding: calc(var(--u) * .5) calc(var(--u) * 1.2);
}

/* -------------------------------- a phone ----------------------------- */
/* A phone is not a small wall. Seven columns across 390 pixels gives day
   squares 50 pixels wide, which hold a color and no words — so below this
   width the month becomes an agenda: today in full, then the week ahead as a
   list you can actually read at arm's length. The grid is one tap away. */
.agenda { display: none; }
.swap   { display: none; }

/* Days are edited in the calendar itself now. The rest of the admin page —
   who is in the family, the night hours, the photograph library — is a rarer
   errand, and this is the way to it. Never on the wall: it appears only where
   someone is signed in and able to change something. */
.more { display: none; }
.more .short { display: none; }

/* .has-cursor is set the first time a mouse moves, .touched the first time
   something is tapped. A wall does neither, so the pill never appears on it —
   even when the wall is signed in and could, in principle, edit. */
body.can-edit.has-cursor .more,
body.can-edit.touched .more,
body.phone.can-edit .more {
  display: inline-block; margin-left: auto;
  font-size: calc(var(--u) * 1.4); font-weight: 700; text-decoration: none;
  padding: calc(var(--u) * .35) calc(var(--u) * 1.1);
  border-radius: 999px; color: var(--ink-dim);
  border: 1px solid var(--glass-edge);
  background: color-mix(in srgb, var(--glass) 55%, transparent);
}
body.can-edit .monthline { display: flex; align-items: center; gap: calc(var(--u) * .8); }
body.phone.can-edit .swap { margin-left: auto; }
body.phone.can-edit .more { margin-left: 0; font-size: calc(var(--u) * 1.6); }

/* The root is overflow:hidden so that a wall can never be scrolled -- there is
   nothing to scroll to, and a stray touch that moved the calendar half a page
   up would stay that way until somebody noticed. A phone has to scroll, and an
   ancestor with a non-visible overflow BETWEEN a sticky element and the
   scrollport is exactly what stops position:sticky from working: the masthead
   was sticky and scrolled away anyway until this was let go. */
html:has(body.phone) { height: auto; overflow: visible; }

body.phone {
  height: auto; overflow-y: visible; overflow-x: clip;
  -webkit-overflow-scrolling: touch;
}
body.phone #app {
  height: auto; min-height: 100%;
  padding: 0 calc(var(--u) * 1.4) 0;
  transform: none;                    /* no burn-in shift: it is not a wall */
}

/* The masthead and today scroll with the page like everything else; only the
   app's own bar and foot (in edit.css -- they do not exist on the wall) stay
   put. They were sticky for a while, and the slab of page color they needed
   behind them read as a black rectangle over the photograph. */
body.phone .grid { flex: 0 0 auto; }
body.phone .weekdays, body.phone .weeks { display: none; }
body.phone .agenda { display: block; }
body.phone.show-month .weekdays { display: grid; }
body.phone.show-month .weeks    { display: grid; }
body.phone.show-month .agenda   { display: none; }

body.phone .swap {
  display: inline-block; margin-left: auto;
  font: inherit; font-size: calc(var(--u) * 1.5); font-weight: 700;
  padding: calc(var(--u) * .4) calc(var(--u) * 1.2);
  border-radius: 999px; cursor: pointer;
  border: 1px solid var(--glass-edge);
  background: color-mix(in srgb, var(--glass) 60%, transparent);
  color: var(--ink-dim);
}
body.phone .monthline { display: flex; align-items: center; gap: calc(var(--u) * .8); }

/* A day of the week ahead: the date, then its entries, or a dash. */
.agenda .aday {
  display: grid; grid-template-columns: 6.5em 1fr;
  gap: calc(var(--u) * .8);
  padding: calc(var(--u) * .9) 0;
  border-top: 1px solid var(--glass-edge);
}
.agenda .aday:first-child { border-top: 0; }
.agenda .adate {
  font-size: calc(var(--u) * 1.6); font-weight: 700; color: var(--ink-dim);
  text-transform: uppercase; letter-spacing: .04em; line-height: 1.3;
}
.agenda .adate small { display: block; font-size: calc(var(--u) * 1.4);
                       font-weight: 600; color: var(--ink-faint); letter-spacing: 0; }
.agenda .aitems { display: flex; flex-direction: column; gap: calc(var(--u) * .5); }
.agenda .aitem {
  display: grid; grid-template-columns: 5.6em calc(var(--u) * .45) 1fr;
  gap: calc(var(--u) * .7); align-items: center;
}
.agenda .aitem .at { font-size: calc(var(--u) * 1.5); color: var(--ink-dim); }
.agenda .aitem .ab { align-self: stretch; border-radius: 999px;
                     background: var(--c, var(--blue)); min-height: calc(var(--u) * 2); }
.agenda .aitem .an { font-size: calc(var(--u) * 1.8); font-weight: 600; }
.agenda .aitem .aw { font-size: calc(var(--u) * 1.35); color: var(--ink-faint); }
.agenda .anone { font-size: calc(var(--u) * 1.5); color: var(--ink-faint); font-style: italic; }



/* ------------------------------ paper look ---------------------------- */
/* A second way of drawing the same calendar, for a monitor in a wooden frame.
   Nothing here touches the glass rules: every selector below is scoped to
   [data-style="paper"], so switching the setting switches the look and
   switching it back leaves the wall display exactly as it was.
   
   The idea is print, not glass. A sheet of paper has no floating panes, no
   blur, no glow and no rounded rectangles — it has ink, hairline rules and
   generous margins. So the panels stop being objects and become regions, and
   the month grid stops being a set of cards with gaps and becomes a ruled
   table, which is what a wall calendar actually is. */
body[data-style="paper"] {
  --ink:       #26221b;
  --ink-dim:   #5f5648;
  --ink-faint: #8d8372;
  /* The red a printed calendar uses for holidays and for today. */
  --today:     #a63d28;
  --house:     #4f5a62;
  --page:      #f6f1e6;
  --lift:      0 calc(var(--u) * .12) calc(var(--u) * .36) rgba(70, 55, 35, .15),
               0 calc(var(--u) * .7)  calc(var(--u) * 1.9) rgba(70, 55, 35, .11);
  --rule:        rgba(58, 48, 34, .22);
  --rule-strong: rgba(58, 48, 34, .42);
  --shadow: none;
  --sheet:     #f6f1e6;
  --card:      #f6f1e6;
}
body[data-theme="night"][data-style="paper"] {
  --ink:       #d8cfbe;
  --ink-dim:   #9d927f;
  --ink-faint: #6e6555;
  --today:     #c86a4e;
  --house:     #93a4b4;
  --page:      #14110d;
  --lift:      0 calc(var(--u) * .12) calc(var(--u) * .36) rgba(0, 0, 0, .55),
               0 calc(var(--u) * .7)  calc(var(--u) * 1.9) rgba(0, 0, 0, .40);
  --rule:        rgba(216, 207, 190, .16);
  --rule-strong: rgba(216, 207, 190, .30);
  --sheet:     #211d17;
  --card:      #3a332a;
  --today-track: rgba(255, 255, 255, .07);
}

/* Serif for the things a printed calendar sets in serif — the month, the day,
   the quote. Numbers stay in the sans, as they do in print, because a ruled
   grid of dates wants an even, tabular figure. DejaVu and Liberation are what
   a Raspberry Pi actually has; Georgia and Palatino are for everywhere else. */
body[data-style="paper"] .dow,
body[data-style="paper"] .monthline .m,
body[data-style="paper"] .quote,
body[data-style="paper"] .today-panel h2,
body[data-style="paper"] .fact {
  font-family: "Iowan Old Style", "Palatino Linotype", Palatino, Georgia,
               "DejaVu Serif", "Liberation Serif", "Times New Roman", serif;
}
/* The masthead. A printed calendar sets the day large and the date beneath it
   as a subhead; the clock is the one thing on the page that is not print, so
   it stays light and gets out of the way. */
body[data-style="paper"] .dow {
  letter-spacing: -.022em;
  font-weight: 700;
  line-height: .96;
}
body[data-style="paper"] .dm {
  letter-spacing: .01em;
  font-weight: 500;
  color: var(--ink-dim);
}
/* The serif masthead is much wider than the sans one it replaced, which
   squeezed the clock until AM fell onto its own line. Give the clock a column
   it cannot be squeezed out of, and let the day shrink instead. */
body[data-style="paper"] .head-row { align-items: baseline; gap: calc(var(--u) * 1.4); }
body[data-style="paper"] .head-row > div:first-child { min-width: 0; }
body[data-style="paper"] .clock {
  font-weight: 200; letter-spacing: -.04em;
  flex: 0 0 auto; white-space: nowrap;
}
body[data-style="paper"] .clock small.ampm {
  font-weight: 500; letter-spacing: .1em;
}
/* WEDNESDAY is the widest of the seven, and in a serif at the old size it met
   the clock in the middle. Both come down; the day is still the largest thing
   on the page, which is the point of the masthead. */
body[data-style="paper"] .dow   { font-size: calc(var(--u) * 4.1); }
body[data-style="paper"] .clock { --clock-fs: calc(var(--u) * 4.1); --ap-fs: calc(var(--u) * 1.2); }

/* The two rules I did not put there. The quote and the legend each carry a
   border from the glass stylesheet, which is right when they are separating
   frosted panels and wrong on a sheet of paper — that was three rules stacked
   in the top eighth of the page. */
/* The quote sits BETWEEN two rules, which is a different thing from having a
   rule under it: bracketed, the line reads as a pulled quotation rather than
   as a caption hanging off the date above it. */
body[data-style="paper"] .quote {
  font-style: italic;
  line-height: 1.5;
  color: var(--ink-dim);
  border-top: 1px solid var(--rule);
  padding-top: calc(var(--u) * 1.1);
  margin-top: calc(var(--u) * 1.1);
}
body[data-style="paper"] .legend {
  border-top: 0;
  padding-top: 0;
  margin-top: calc(var(--u) * 1.2);
  font-size: calc(var(--u) * 1.25);
  letter-spacing: .02em;
}
body[data-style="paper"] .fact { line-height: 1.5; }

/* Panels become regions: no fill, no blur, no float. A rule where a printed
   calendar would put one, and nothing where it would not. */
body[data-style="paper"] .glass {
  background: transparent;
  border: 0;
  border-radius: 0;
  box-shadow: none;
  backdrop-filter: none;
  -webkit-backdrop-filter: none;
  /* One left margin for the whole page.
     Each panel carries its own horizontal padding, which is right when they
     are separate frosted objects and wrong on a sheet: it gave the masthead a
     different left edge from the month, and the rules drawn across them then
     started and stopped in different places. The page margin is #app's now,
     and everything lines up against it. */
  padding-left: 0;
  padding-right: 0;
}
body[data-style="paper"] #scrim { background: none; }
body[data-style="paper"] #app { gap: 0; padding: calc(var(--u) * 2.4) calc(var(--u) * 2.6); }

/* ONE rule on the page, under the masthead, and it earns its place by
   separating the date from everything the date is about. Every other division
   is done with space, which is what a well-set page uses. */
body[data-style="paper"] header.glass {
  border-bottom: 1px solid var(--rule);
  padding-bottom: calc(var(--u) * 1.2);
  margin-bottom: calc(var(--u) * 1.6);
}
body[data-style="paper"] .today-panel {
  border: 0;
  padding-bottom: 0;
  margin-bottom: calc(var(--u) * 2);
}
/* And one over the fact, so the foot of the page is closed the same way the
   head of it is. */
body[data-style="paper"] .strip {
  border: 0;
  border-top: 1px solid var(--rule);
  padding-top: calc(var(--u) * 1.1);
  margin-top: calc(var(--u) * 1.4);
}
/* Section headings as small caps rather than as a line with a label on it. */
body[data-style="paper"] .today-panel h2 {
  color: var(--ink-faint);
  font-size: calc(var(--u) * 1.5);
  letter-spacing: .24em;
  font-weight: 600;
  margin-bottom: calc(var(--u) * .6);
}
body[data-style="paper"] .today-panel h2 .count { letter-spacing: .18em; }

/* Entries separated by space, not by a rule between every one of them. */
body[data-style="paper"] .ev { border-top: 0; }
body[data-style="paper"] .tomorrow { border-top: 0; margin-top: calc(var(--u) * .8); }

/* Days are tiles, not table cells.
   A ruled grid is what a ledger looks like; a good printed calendar is closer
   to a set of cards laid on a sheet. Losing the rules loses nothing — the
   spacing already says where one day ends and the next begins — and it takes
   forty-odd lines off a page that had too many. */
body[data-style="paper"] .weekdays {
  gap: calc(var(--u) * .5);
  border: 0;
  padding-bottom: calc(var(--u) * .7);
  font-size: calc(var(--u) * 1.1);
  letter-spacing: .22em;
  font-weight: 600;
  color: var(--ink-faint);
}
body[data-style="paper"] .weeks { gap: calc(var(--u) * .5); border: 0; }
body[data-style="paper"] .week  { gap: calc(var(--u) * .5); }
body[data-style="paper"] .day {
  border: 0;
  border-radius: calc(var(--u) * 1.1);
  /* Ink laid on paper, not a box drawn round it: the tile is a wash a shade
     darker than the sheet, which reads as printed rather than as a container. */
  background: rgba(58, 48, 34, .045);
  padding: calc(var(--u) * .6) calc(var(--u) * .6) calc(var(--u) * .5);
}
body[data-theme="night"][data-style="paper"] .day { background: rgba(216, 207, 190, .05); }
body[data-style="paper"] .day.weekend { background: rgba(58, 48, 34, .075); }
body[data-theme="night"][data-style="paper"] .day.weekend { background: rgba(216, 207, 190, .085); }
body[data-style="paper"] .day.past { opacity: .5; }

/* The date sits quieter than it did — the tile already says it is a day, so
   the numeral does not also have to shout. */
body[data-style="paper"] .day .n {
  font-size: calc(var(--u) * 1.7);
  font-weight: 500;
  letter-spacing: -.01em;
  margin-bottom: calc(var(--u) * .15);
}

/* A day outside this month.
   The grid always spills into the next month — five weeks around today
   practically guarantee it — and it used to say so with a little "SEP" label.
   The square itself is a better place for that: paler stock, lighter ink, no
   text to read. It is still a full square with its entries in it, because a
   thing happening on the 3rd matters whether or not the 3rd is in August. */
body[data-style="paper"] .day.other {
  background: transparent;
  box-shadow: inset 0 0 0 1px var(--rule);
}
body[data-style="paper"] .day.other .n { color: var(--ink-faint); font-weight: 400; }
body[data-style="paper"] .day.other.weekend {
  background: rgba(58, 48, 34, .035);
}
body[data-theme="night"][data-style="paper"] .day.other.weekend {
  background: rgba(216, 207, 190, .04);
}
/* Today wins over all of it, even on the 1st of next month. */
body[data-style="paper"] .day.other.today {
  background: color-mix(in srgb, var(--today) 13%, transparent);
  box-shadow: none;
}
body[data-style="paper"] .day.other.today .n { color: var(--today); font-weight: 700; }

/* In glass the squares are already panes on a background, so the same idea is
   carried by weight rather than by a border. */
body:not([data-style="paper"]) .day.other { opacity: .72; }
body:not([data-style="paper"]) .day.other .n { font-weight: 500; }

/* Today is the one tile that is spoken for: filled in the calendar's red
   rather than ringed, which needs no extra line to say it. */
body[data-style="paper"] .day.today {
  background: color-mix(in srgb, var(--today) 13%, transparent);
  box-shadow: none;
}
body[data-style="paper"] .day.today .n { color: var(--today); font-weight: 700; }

/* An entry is a line of ink with a colored rule beside it — the same shape the
   legend uses, so the two still explain each other. A filled tint block would
   read as a screen element; a rule reads as print. */
body[data-style="paper"] .chip {
  background: transparent;
  border-radius: 0;
  padding: 0 0 0 calc(var(--u) * .5);
  border-left: calc(var(--u) * .34) solid var(--c, var(--blue));
  color: var(--ink);
}
body[data-style="paper"] .chip.all {
  background: color-mix(in srgb, var(--c, var(--blue)) 18%, transparent);
  font-weight: 700;
}
body[data-style="paper"] .legend span {
  background: transparent;
  border-radius: 0;
  padding: 0 0 0 calc(var(--u) * .5);
  border-left: calc(var(--u) * .34) solid var(--c, var(--gray));
  color: var(--ink-dim); font-weight: 700;
}

/* Today's list: the color bar stays, everything else loses its screen-ness.
   Rounded ends are the last thing that gives a printed sheet away — ink laid
   down by a press has square corners, and a lozenge reads as a UI badge no
   matter what color it is. */
body[data-style="paper"] .ev { border-top-color: var(--rule); }
body[data-style="paper"] .ev .bar { border-radius: 0; }
/* No box. A bordered pill is a button everywhere else on a screen, and this is
   a countdown printed beside a line of type. */
body[data-style="paper"] .ev .in {
  background: transparent;
  border: 0;
  border-radius: 0;
  padding: 0;
  color: var(--ink-faint);
  font-weight: 500;
  font-style: italic;
}
body[data-style="paper"] .ev .in.happening { border-color: var(--today); color: var(--today); }
/* A wall calendar has no clock on it, but this one has to earn its screen —
   so the time stays and merely stops being the thinnest thing on the page. */
body[data-style="paper"] .clock { font-weight: 300; color: var(--ink); }

/* The sheet is the background in this mode; a photograph behind printed ink
   would be a different thing entirely. */
body[data-style="paper"].has-photo #bg { filter: none; }

/* ------------------------------- the ribbon --------------------------- */
/* The shape of a day, on one line.
   A list tells you what is on; it does not tell you that the afternoon is
   free, or that everyone is out at once between four and six. Blocks placed
   by time say both without a word — so there are no words in here beyond the
   hour numerals, and the names stay in the list underneath where there is
   room to read them. */
.ribbon { flex: 0 0 auto; margin-bottom: calc(var(--u) * 1.1); }

/* All-day entries have no position, so they are a rule across the whole day
   rather than a block within it. */
.ribbon .allday { display: flex; gap: calc(var(--u) * .3); margin-bottom: calc(var(--u) * .45); }
.ribbon .allday i {
  flex: 1 1 0; height: calc(var(--u) * .5);
  background: var(--c, var(--blue)); opacity: .85;
}

.ribbon .band {
  position: relative;
  height: calc(var(--u) * 2.6);
  border-bottom: 1px solid var(--rule, var(--glass-line));
}
/* The part of the day already gone, grayed back so "now" reads as a position
   and not just a mark. */
.ribbon .gone {
  position: absolute; left: 0; top: 0; bottom: 0;
  background: currentColor; opacity: .06;
}
.ribbon .blk {
  position: absolute; top: calc(var(--u) * .35); bottom: calc(var(--u) * .35);
  background: var(--c, var(--blue));
  min-width: calc(var(--u) * .55);
}
.ribbon .blk.past { opacity: .38; }

/* Now: a full-height rule in the calendar's red, with a tick below the line so
   it still reads when it lands on top of a block. */
.ribbon .now {
  position: absolute; top: 0; bottom: calc(var(--u) * -.5); width: 2px;
  background: var(--today);
}
.ribbon .now::after {
  content: ""; position: absolute; left: 50%; bottom: 0;
  transform: translateX(-50%);
  border-left: calc(var(--u) * .42) solid transparent;
  border-right: calc(var(--u) * .42) solid transparent;
  border-bottom: calc(var(--u) * .5) solid var(--today);
}

.ribbon .hours { position: relative; height: calc(var(--u) * 1.6); }
.ribbon .hours span {
  position: absolute; top: calc(var(--u) * .25);
  transform: translateX(-50%);
  font-size: calc(var(--u) * 1.15);
  color: var(--ink-faint);
  font-variant-numeric: tabular-nums;
}
.ribbon .hours i {
  position: absolute; top: 0; width: 1px; height: calc(var(--u) * .35);
  background: var(--rule, var(--glass-line));
}

/* ---- the spine: the day read downwards ---- */
.ribbon.spine { flex: 1 1 auto; min-height: 0; overflow: hidden; margin-bottom: 0; }
.ribbon .spine { display: flex; flex-direction: column; }

/* Entry rows and gap rows share one grid so the rule runs unbroken down the
   middle of both. */
.ribbon .sr, .ribbon .sg {
  display: grid;
  grid-template-columns: calc(var(--u) * 6.4) calc(var(--u) * .9) minmax(0, 1fr);
  gap: calc(var(--u) * 1.1);
  align-items: stretch;
}
.ribbon .sr { padding: calc(var(--u) * .45) 0; }

.ribbon .st {
  font-size: calc(var(--u) * 1.7); font-weight: 600; color: var(--ink-dim);
  text-align: right; white-space: nowrap; padding-top: calc(var(--u) * .1);
  font-variant-numeric: tabular-nums;
}
/* The rule itself, with the entry's own stretch of it inked in. */
.ribbon .sb { position: relative; display: flex; justify-content: center; }
.ribbon .sb::before {
  content: ""; position: absolute; top: 0; bottom: 0; width: 1px;
  background: var(--rule, var(--glass-line));
}
.ribbon .sb i {
  position: relative; width: calc(var(--u) * .42); align-self: center;
  background: var(--c, var(--blue)); min-height: calc(var(--u) * 1.4);
}
.ribbon .snt { font-size: calc(var(--u) * 2.1); font-weight: 600; line-height: 1.2; }
.ribbon .snw { font-size: calc(var(--u) * 1.4); color: var(--ink-faint); line-height: 1.3; }

/* Something that begins before the thing above it has ended is drawn
   indented, hung off the rule by a short elbow. A day of clashes should read
   as clashes; without this the spine lists them as a tidy queue and quietly
   tells you the afternoon is free. */
.ribbon .sr.nest .sn { position: relative; padding-left: calc(var(--u) * 1.6); }
.ribbon .sr.nest .sn::before {
  content: ""; position: absolute; left: 0; top: calc(var(--u) * 1.05);
  width: calc(var(--u) * .9); height: 1px;
  background: var(--rule, var(--glass-line));
}
.ribbon .sr.nest .snt { font-size: calc(var(--u) * 1.85); }
.ribbon .spine.tight .sr.nest .snt { font-size: calc(var(--u) * 1.65); }

.ribbon .sr.past { opacity: .45; }
.ribbon .sr.past .snt { font-weight: 500; }
.ribbon .sr.running .snt { font-weight: 700; }

/* Gaps: three heights, so an hour free and a whole afternoon free do not look
   the same, without pretending to be to scale. */
.ribbon .sg.g1 { height: calc(var(--u) * 1.1); }
.ribbon .sg.g2 { height: calc(var(--u) * 2.4); }
.ribbon .sg.g3 { height: calc(var(--u) * 4.2); }
.ribbon .sg.g0 { height: calc(var(--u) * .5); }
/* Last resort, after the gaps have given all they can. */
.ribbon .spine.tight .sr { padding: calc(var(--u) * .2) 0; }
.ribbon .spine.tight .snt { font-size: calc(var(--u) * 1.85); }
.ribbon .spine.tight .snw { font-size: calc(var(--u) * 1.25); }
.ribbon .spine.tight .st  { font-size: calc(var(--u) * 1.5); }
.ribbon .sg.nowgap { height: calc(var(--u) * 1.6); }
.ribbon .sg .nowrule { grid-column: 2 / 4; align-self: center; position: relative; height: 2px; }
.ribbon .sg .nowrule::before {
  content: ""; position: absolute; left: 0; right: 0; top: 50%;
  height: 2px; background: var(--today);
}
.ribbon .sg .nowrule::after {
  content: ""; position: absolute; left: calc(var(--u) * .45); top: 50%;
  width: calc(var(--u) * .8); height: calc(var(--u) * .8);
  transform: translate(-50%, -50%); border-radius: 50%;
  background: var(--today);
}
.ribbon .sr.running .sb i { box-shadow: 0 0 0 2px color-mix(in srgb, var(--today) 55%, transparent); }

/* ---- lines: a row each, so a collision is a thing you can see ---- */
.ribbon .lines {
  /* max-content: the names decide how wide their column is, so nobody is
     clipped and nothing is padded out for a name that is not there. */
  display: grid; grid-template-columns: max-content 1fr;
  column-gap: calc(var(--u) * .9); row-gap: 0;
}
/* The hours belong to the tracks, not to the names, so they sit under the
   second column and line up with what they measure whatever the names do. */
.ribbon .lines > .hours { grid-column: 2; }
.ribbon .labels, .ribbon .tracks {
  display: flex; flex-direction: column; gap: calc(var(--u) * .3);
}
/* Rows are no longer all one height, so the initials stretch to match rather
   than drifting away from the tracks they name. */
.ribbon .labels { align-items: stretch; }
.ribbon .labels span { display: flex; align-items: center; justify-content: flex-end; }
/* One positioning context for every track, so the now-rule is drawn once. */
.ribbon .tracks { position: relative; }
.ribbon .labels span {
  height: calc(var(--u) * 1.1);
  font-size: calc(var(--u) * 1.15); font-weight: 600;
  color: var(--c, var(--ink-dim)); letter-spacing: .01em;
  white-space: nowrap;
}
.ribbon .labels span.stacked2 { height: calc(var(--u) * 1.9); }
.ribbon .labels span.stacked3 { height: calc(var(--u) * 2.6); }
.ribbon .track {
  position: relative; height: calc(var(--u) * 1.1);
  border-bottom: 1px solid var(--rule-soft, var(--glass-line));
}
/* A row grows when the person it belongs to is in two places at once. */
.ribbon .track.stacked2 { height: calc(var(--u) * 1.9); }
.ribbon .track.stacked3 { height: calc(var(--u) * 2.6); }
.ribbon .track .blk { top: 0; bottom: 0; }
/* The rule spans the whole stack; only the arrowhead sits below it. */
.ribbon .tracks > .now { top: 0; bottom: calc(var(--u) * -.45); }

/* ------------------------------ the week -------------------------------
   Seven vertical bands, time running down them, on one scale so that ten
   o’clock on Tuesday is level with ten o’clock on Friday. That is the whole
   point: you read the week’s SHAPE off the gaps -- which days are solid, which
   are open, whether the busy ones are mornings or evenings -- without reading a
   single word. The same idea as the day’s swimlanes, turned ninety degrees.
   Titles appear inside a block only when the block is tall enough to hold one;
   the color says who in every case, which is what carries at four metres. */
.weekrows {
  flex: 1 1 auto; min-height: 0;
  /* The hour scale, then one column per day -- however many days that is. */
  display: grid;
  grid-template-columns: calc(var(--u) * 1.9) repeat(var(--days, 7), minmax(0, 1fr));
  gap: calc(var(--u) * .35);
  /* No overflow:hidden here. Today is a raised card that leans half a unit out
     of its column on every side, and clipping the row shaved its top and
     bottom off against the month name above and the legend below. Everything
     that needs trimming inside a day is trimmed by .wbtrack's own overflow. */
}
.weekrows[hidden], .weeks[hidden], .weekdays[hidden] { display: none; }

.wbhours { display: flex; flex-direction: column; min-width: 0; }
.wbscale { position: relative; flex: 1 1 auto; min-height: 0; }
.wbscale span {
  position: absolute; right: 0; transform: translateY(-50%);
  font-size: calc(var(--u) * 1.1); color: var(--ink-faint);
  font-variant-numeric: tabular-nums; line-height: 1;
}

/* Today is a whole column, not a colored word. Among eleven bands a date in a
   different ink is something you have to go looking for; a lit column is what
   your eye lands on before it has read anything. The tint sits behind the
   heading and the track together, which is what makes it read as one day
   rather than as two things that happen to be stacked. */
.wbday { display: flex; flex-direction: column; min-width: 0; cursor: pointer;
         border-radius: calc(var(--u) * .5); }
/* Today is a card, not a tint.
   A wash of warm color over the column says "this one is slightly different";
   from the other end of a hall that reads as a printing fault rather than as
   now. Lifting it off the page says today is a different KIND of thing from
   the six days around it, which is what it is.
   The widening is a negative margin rather than a wider column, because
   .weekrows is a GRID -- the columns are repeat(minmax(0, 1fr)) and there is
   no flex-grow to lean on. Growing into the gutters gets the same half-unit of
   extra width without any of the seven tracks moving.
   z-index so the shadow falls ON Thursday and Saturday rather than under
   them: a card that is lifted but casts nothing is just a lighter rectangle. */
.wbday.today {
  position: relative; z-index: 1;
  /* Not fully opaque: on the photograph palette a solid card would punch a
     hole in the picture the panels are deliberately letting through.
     --card, not --sheet: at night the sheet is DARKER than the panels around
     it, and a raised card cut from it read as a hole. The night themes give
     the card a surface a step lighter than everything else, which is what
     "catching the light" means in a dark room. */
  background: color-mix(in srgb, var(--card, var(--sheet)) 92%, transparent);
  border-radius: calc(var(--u) * .9);
  /* A shadow alone is how a light theme says "raised". A dark one cannot use
     it -- a shadow on near-black is invisible -- so the card also carries the
     lit edge every other panel here uses, which is what actually reads as
     elevation once the room is dark. */
  box-shadow: var(--lift), inset 0 0 0 1px var(--glass-edge);
  padding: calc(var(--u) * .5) calc(var(--u) * .45) calc(var(--u) * .45);
  margin: calc(var(--u) * -.5) calc(var(--u) * -.5) calc(var(--u) * -.45);
}
/* The warmth moves inside, onto the track, where it tints the day's own hours
   rather than the whole column. */
/* The warm wash belongs to daylight. Over the night card it made mud -- amber
   at 18% on a lifted brown is a stain, not a highlight -- so the dark themes
   swap it for a plain lift and let the card, its lit edge and the red date do
   the pointing. */
.wbday.today .wbtrack {
  background: var(--today-track, var(--today-soft));
  border-radius: calc(var(--u) * .55);
}
.wbh {
  flex: 0 0 auto; text-align: center; line-height: 1.05;
  padding-bottom: calc(var(--u) * .5);
}
.wbh i {
  display: block; font-style: normal;
  font-size: calc(var(--u) * 1.05); text-transform: uppercase; letter-spacing: .07em;
  color: var(--ink-faint); font-weight: 700;
}
.wbh b { display: block; font-size: calc(var(--u) * 1.9); font-weight: 600; }
.wbday.today .wbh i, .wbday.today .wbh b { color: var(--today); }
.wbday.past .wbh { opacity: .55; }

/* The band itself: a column of time with a faint ground so an empty day still
   reads as a day rather than as nothing. */
.wbtrack {
  position: relative; flex: 1 1 auto; min-height: 0;
  background: var(--glass-2, rgba(128,128,128,.06));
  border-radius: calc(var(--u) * .4);
  overflow: hidden;
}
/* No second tint on the track: the column behind it is already the highlight,
   and two warm washes over each other turn the blocks inside to mud. */
.wbday.weekend .wbtrack { background: var(--glass-2, rgba(128,128,128,.06)); opacity: .75; }

.wbblk {
  position: absolute; border-radius: calc(var(--u) * .25);
  background: var(--c, var(--blue));
  overflow: hidden; padding: 0 calc(var(--u) * .18);
  box-sizing: border-box;
}
.wbblk.past { opacity: .42; }
/* The line between two things happening at once.
   A transparent border with the background clipped to the padding box, rather
   than a colored one: what shows through is whatever is actually behind the
   block, so it is right in all four palettes and needs no token of its own.
   box-sizing is border-box everywhere here, so the block does not move or
   change width to make room for it. */
.wbblk.abuts {
  border-left: 2px solid transparent;
  background-clip: padding-box;
}
/* A title uses the height it is given. A two-hour block is four lines tall and
   was spending three of them on nothing while the name said "Caspar C..." on
   the first. It wraps now, clamped to whatever number of lines actually fits --
   the rectangle is the tide of the day and must not grow to suit its label, so
   the text is what gives way. */
.wbblk span {
  display: -webkit-box; -webkit-box-orient: vertical;
  -webkit-line-clamp: var(--lines, 1);
  font-size: calc(var(--u) * 1.05); line-height: 1.14;
  color: #fff; font-weight: 600;
  overflow: hidden; overflow-wrap: anywhere;
}
/* Two lanes deep the block is too narrow for a word, so it stops pretending. */
.wbblk[style*="width: 50"] span, .wbblk[style*="width: 33"] span { display: none; }

.wball { position: absolute; inset: 0 0 auto 0; display: flex; gap: 1px;
         padding: calc(var(--u) * .12); }
.wball i { flex: 1 1 0; height: calc(var(--u) * .5); border-radius: 999px;
           background: var(--c, var(--blue)); }

.wbnow { position: absolute; left: 0; right: 0; height: 2px; background: var(--today); }
.wbnow::before {
  content: ""; position: absolute; left: 0; top: 50%;
  width: calc(var(--u) * .55); height: calc(var(--u) * .55);
  transform: translate(-30%, -50%); border-radius: 50%; background: var(--today);
}

/* Not `opacity`, which fades the whole subtree: the entries inside the track
   were being washed out along with the paper they sat on, which is why every
   block in the week has been a pale gray rather than its person's color.
   --rule is already translucent, so it tints on its own. */
body[data-style="paper"] .wbtrack {
  background: color-mix(in srgb, var(--rule) 38%, transparent);
  border-radius: 0;
}
/* Paper keeps its square corners everywhere else -- it is meant to look
   printed -- but today is the one thing on the page that is not printed, and
   square corners on a raised card read as a misprint rather than as a card. */
body[data-style="paper"] .wbday.today { border-radius: calc(var(--u) * .8); }
body[data-style="paper"] .wbblk { border-radius: 0; }

/* Seven bands do not need the height seven rows of writing did, and the strip
   below them does: a tide curve and a sun's arc are shapes, and a shape half a
   centimetre tall is a smudge. So in week mode the coast takes more and the
   week gives it back. */
body.week-grid .c-art { height: calc(var(--u) * 5.6); }
body.week-grid .coast { padding-top: calc(var(--u) * 1.3); padding-bottom: calc(var(--u) * 1.3); }

/* Stacked, the week does not want everything today leaves it. A band is read
   for its proportions, not its size: at forty percent of a portrait screen the
   same seven days say nothing more than they do at twenty, and they take the
   room off the day you are actually standing there to read. So the week is
   capped, the panel shrinks to it, and today's list absorbs what is freed
   rather than leaving a hole in the middle of the wall. */
/* A height, not a max-height: the bands have no size of their own -- a track
   is a proportion of whatever it is given -- so in a panel that shrinks to its
   contents they shrink to nothing. */
body.week-grid:not(.lay-landscape) .weekrows   { flex: 0 1 auto; height: 21vh;
                                                 min-height: calc(var(--u) * 9); }
/* Who gives way, and in what order. The week goes first and by three times as
   much: with today unshrinkable the strip and the fact walked off the bottom
   of the screen, and with today the ONLY shrinkable thing every pixel the
   layout was short came out of the day you are standing there to read. */
body.week-grid:not(.lay-landscape) .grid        { flex: 0 3 auto; }
body.week-grid:not(.lay-landscape) .today-panel { flex: 1 1 auto; max-height: 62%; }

/* Stacked, the week gets whatever today leaves, and that is a shallow strip.
   It is still seven whole days: bands scale with their track, so a short band
   is a small picture of the week rather than a clipped one -- which is exactly
   why the list this replaced could not survive down here and this can. Forcing
   it taller only pushes it over the strip below; today does not give the room
   back, and an overlap is worse than a squat week. */

/* --------------------------- the days ahead --------------------------- */
/* Landscape gives today a whole column, and two entries do not fill a column.
   The old layout stretched the list and pinned TOMORROW to the floor, which
   left a naked gap down the middle of the wall with one orphaned line under
   it. So: today, then the days after it, then space — in that order, from the
   top, the way a page is read. */
.ahead { display: none; }
body[data-style="paper"] #todayList { flex: 0 0 auto; }

  body.lay-landscape[data-style="paper"] .ahead {
    display: block;
    margin-top: calc(var(--u) * 1.6);
  }
  /* One line saying "tomorrow" is redundant once the days after today are
     listed in full. */
  body.lay-landscape[data-style="paper"] .tomorrow { display: none; }


.ahead .ah {
  display: grid; grid-template-columns: 5.4em 1fr;
  gap: calc(var(--u) * 1.2);
  padding: calc(var(--u) * .75) 0;
  align-items: start;
}
.ahead .ahd {
  font-size: calc(var(--u) * 1.5);
  letter-spacing: .16em; text-transform: uppercase;
  color: var(--ink-dim); font-weight: 700;
  white-space: nowrap; line-height: 1.25;
}
.ahead .ahd small {
  display: block;
  font-size: calc(var(--u) * 1.35);
  letter-spacing: .02em; font-weight: 500; text-transform: none;
  color: var(--ink-faint);
}
.ahead .ahi { display: flex; flex-direction: column; gap: calc(var(--u) * .45); }
.ahead .ahe {
  display: grid; grid-template-columns: 6.6em calc(var(--u) * .34) 1fr;
  gap: calc(var(--u) * .7); align-items: center;
}
.ahead .ahe .t {
  font-size: calc(var(--u) * 1.5); color: var(--ink-dim); white-space: nowrap;
}
.ahead .ahe .b {
  align-self: stretch; min-height: calc(var(--u) * 1.9);
  background: var(--c, var(--blue));
}
.ahead .ahe .n { font-size: calc(var(--u) * 1.75); font-weight: 500; }
.ahead .ahn { font-size: calc(var(--u) * 1.5); color: var(--ink-faint); font-style: italic; }

/* A laptop is landscape and half the height; keep it legible while working. */
/* Trouble is rare and never part of the layout: it floats over whichever one is
   in use rather than taking a row in it. */
.trouble {
  position: fixed; left: 50%; bottom: calc(var(--u) * 1.6);
  transform: translateX(-50%); z-index: 3;
}

/* ---------------------------------------------------------------------------
   Landscape.
   A wide screen is not a tall one turned sideways. The quote sits across the
   top of the left column with the month under it and the fact under that; the
   date and the day's entries take the right. The month gets only the width its
   seven columns need to stay readable — the day is a list of sentences and
   wants the rest.
   --------------------------------------------------------------------------- */
  body.lay-landscape { --u: 1.5vh; }

  body.lay-landscape #app {
    display: grid;
    /* The month only needs seven columns wide enough to read a name in; the
       day is a list of sentences and wants the room. */
    grid-template-columns: minmax(0, 0.92fr) minmax(0, 1fr);
    grid-template-rows: auto minmax(0, 1fr) auto auto;
    grid-template-areas:
      "month  head"
      "month  today"
      "coast  today"
      "fact   today";
    gap: calc(var(--u) * 1.2);
  }
  body.lay-landscape .grid { grid-area: month; }
  body.lay-landscape header { grid-area: head; }
  body.lay-landscape .today-panel { grid-area: today; max-height: none; }
  body.lay-landscape .coast { grid-area: coast; }
  body.lay-landscape .strip { grid-area: fact; }

  /* The header is a column now, not a band across the top. */
  body.lay-landscape header { padding: calc(var(--u) * 1.3) calc(var(--u) * 1.8); }
  body.lay-landscape[data-style="paper"] header { padding-left: 0; padding-right: 0; }
  /* Paper zeroes #app's gap for the single-column case, and that rule outranks
     this media query on specificity rather than order — so with the panel
     padding also gone, the month ran straight into today's column. Two columns
     on a sheet need a gutter, and it is wider than a gap between panes would
     be: there is no edge or shadow here to say where one ends. */
  body.lay-landscape[data-style="paper"] #app {
    column-gap: calc(var(--u) * 4.5);
    row-gap: calc(var(--u) * 1.2);
  }
  body.lay-landscape .dow { font-size: calc(var(--u) * 4.2); }
  body.lay-landscape .dm { font-size: calc(var(--u) * 2.2); }
  body.lay-landscape .clock { --clock-fs: calc(var(--u) * 4.6); }
  body.lay-landscape .ev { padding: calc(var(--u) * .6) 0; }

@media (max-width: 560px) {
  .more .long  { display: none; }
  .more .short { display: inline; }
}

/* ---------------------------------------------------------------------------
   A phone — LAST in the file, and it has to be.
   These override rules written further up, several of which are
   body[data-style="paper"] .x — exactly the specificity of the ones in here.
   Equal specificity means ORDER decides, so anything above the paper section
   matches and then loses. The symptom was a serif masthead running off the
   right edge of a phone while the rule that would have shrunk it sat higher up
   the file, doing nothing.
   --------------------------------------------------------------------------- */
@media (max-width: 560px) {
  /* The wall's unit is a slice of HEIGHT, which is right for a panel whose
     width is never the constraint. On a phone held upright the width is the
     only constraint, so the unit follows whichever is smaller and the whole
     scale comes down with it. */
  :root { --u: min(1.05vh, 2vw); }
  body { cursor: default; }

  /* Today was capped at just over half the glass so a week always showed
     beneath it. On a phone the page scrolls, so nothing is competing for the
     room and the day gets to be as long as it is. */
  .today-panel { max-height: none; }

  /* Six units of a wall is a headline; six units of a phone is still too much
     next to a clock. These are the few places sized for a room. */
  .dow   { font-size: calc(var(--u) * 4.2); }
  .clock { --clock-fs: calc(var(--u) * 4.4); --ap-fs: calc(var(--u) * 1.25); }
  .dm    { font-size: calc(var(--u) * 2.1); }

  /* The time column was 12.5 units wide because a wall reads it from four
     metres. In a hand it only has to hold "10:30 AM". */
  .ev { grid-template-columns: minmax(calc(var(--u) * 8.6), max-content)
                               calc(var(--u) * .7) minmax(0, 1fr) auto; }
  .ev .when      { font-size: calc(var(--u) * 1.7); }
  .ev.next .when { font-size: calc(var(--u) * 1.8); }
  .ev.now   .what { font-size: calc(var(--u) * 2.1); }
  .ev.next  .what { font-size: calc(var(--u) * 2.4); }
  .ev.later .what { font-size: calc(var(--u) * 2.0); }
  .ev .in { font-size: calc(var(--u) * 1.5); }

  /* Only ever seen in a hand, so it may as well be sized for one. */
  .agenda .aday   { grid-template-columns: 5.2em 1fr; }
  .agenda .adate  { font-size: calc(var(--u) * 1.9); }
  .agenda .adate small { font-size: calc(var(--u) * 1.7); }
  .agenda .aitem  { grid-template-columns: 5.4em calc(var(--u) * .5) 1fr; }
  .agenda .aitem .at { font-size: calc(var(--u) * 1.8); }
  .agenda .aitem .an { font-size: calc(var(--u) * 2.1); }
  .agenda .aitem .aw { font-size: calc(var(--u) * 1.6); }
  .agenda .anone  { font-size: calc(var(--u) * 1.8); }
  .swap  { font-size: calc(var(--u) * 1.8) !important; }

  /* Paper on a phone.
     The paper rules above are written as body[data-style="paper"] .x, which
     outranks a bare .x in here however late it comes — so the phone sizes were
     being ignored and the serif masthead ran off the right edge along with the
     clock, the entry count and the buttons. Same specificity, and they fit. */
  body[data-style="paper"] .dow   { font-size: calc(var(--u) * 3.1); }
  /* The fifth and last place a clock size is set: paper, on a phone. This one
     is why the AM floated -- it shrank the numerals to 2.5u while the offset
     above them was still being worked out from the 4.1u paper size. */
  body[data-style="paper"] .clock { --clock-fs: calc(var(--u) * 2.5);
                                    --ap-fs:    calc(var(--u) * 1.2); }
  body[data-style="paper"] .dm    { font-size: calc(var(--u) * 1.9); }
  body[data-style="paper"] .quote { font-size: calc(var(--u) * 1.6); }
  /* Wide tracking is a luxury of a wide screen. */
  body[data-style="paper"] .today-panel h2 { letter-spacing: .12em; font-size: calc(var(--u) * 1.4); }
  body[data-style="paper"] .weekdays { letter-spacing: .1em; }
  body[data-style="paper"] .monthline { flex-wrap: wrap; row-gap: calc(var(--u) * .6); }
  /* No bottom padding on a phone: the sticky foot cannot enter its
     parent's padding, so any padding here is a gap it floats above. */
  body[data-style="paper"] #app { padding: 0 calc(var(--u) * 1.6) 0; }
}

