:root {
  --green: #00824c;
  --ink: #1a1d21;
  --muted: #6b7378;
  --line: #eceff2;
  --bg: #fbfbfd;
  /* Pixels per hour of the day rail. Percentage-based top/height (js/dayview.js)
     scale off of this via --hours, so a block's pixel size tracks the duration it
     represents instead of being squeezed by how many hours the day happens to span.
     Two prior calibrations (100px/hour, then 135px/hour) each modeled content height
     as a function of {duration, roomStatus, line counts} sampled or enumerated from
     the data as it existed at the time -- but content height also depends on
     *rendered width*, which depends on how many events overlap. Neither calibration
     accounted for that: a narrower column (2-way overlap = 50% width) can force a
     long course name to wrap onto extra lines that never appeared at full width,
     which is exactly what happened on 2026-11-03 (see .superpowers/sdd/
     fix-content-clamp-report.md). Do not recalibrate by sampling/enumerating shapes
     at full width again.
     The real fix is structural, in the .event rules below: .course is clamped to 2
     lines, .activity/.teachers/.note are clamped to 1 line with ellipsis, and .rooms
     is a non-wrapping row -- so a block's content height now depends only on which
     fields are present, never on name length or column width. Verified in a real
     browser: the same synthetic worst-case event (longest real course name, a
     teacher list, a note, and an assigned room all present at once, at the
     shortest real duration, 45min) measures the *same* content height at 50%, 33%
     and 25% column width (147.5px, 98.3px, 73.75px at 375px viewport) -- 121px.
     That is the true worst case, not a sampled one: it is every optional line the
     renderer can produce, present at once, at the tightest duration in the data.
     121px / 0.75h = 161.33px/hour is the exact floor (measured boundary: 160px/hour
     still clips that synthetic case, 161px/hour does not). 180px/hour clears it with
     ~12% headroom. This number is invalidated only by: a new field added to
     renderEvent() without a line-clamp/nowrap bound, a duration shorter than 45min
     appearing in the data, or a font/line-height change in .event -- recheck by
     rerunning the all-dates + synthetic-worst-case harness described in the report. */
  --hour-height: 180px;
  font-family: -apple-system, "Segoe UI", Roboto, sans-serif;
}

* { box-sizing: border-box; }
body { margin: 0; background: var(--bg); color: var(--ink); }

.bar {
  background: var(--green); color: #fff;
  padding: .7rem 1rem; padding-top: max(.7rem, env(safe-area-inset-top));
  display: flex; justify-content: space-between; align-items: center;
  font-weight: 700;
}
.bar button {
  background: rgba(255,255,255,.18); color: #fff; border: 0;
  border-radius: 6px; padding: .3rem .7rem; font: inherit; font-size: .85rem;
}

.nav {
  display: flex; justify-content: space-between; align-items: center;
  padding: .55rem 1rem; background: #fff; border-bottom: 1px solid #e3e8ec;
  font-weight: 700;
}
.nav button {
  background: var(--line); border: 0; border-radius: 6px;
  width: 2rem; height: 2rem; font-size: 1.1rem; color: #41474d;
}
.nav button:disabled { opacity: .35; }

main { padding: .5rem 1rem 2rem; }

/* --hours is set by js/dayview.js from layoutDay's hours array (span in hours
   between the day's first and last axis line), so pixel height scales with how
   long the day actually is. The page scrolls vertically past this rather than
   squeezing every event into a fixed-height band. The floor guards a very short
   day (e.g. a single one-hour slot) from producing a cramped rail. */
.rail { position: relative; margin-left: 3rem; height: max(320px, calc(var(--hours, 10) * var(--hour-height))); }
.hour { position: absolute; left: 0; right: 0; border-top: 1px solid var(--line); }
.hour-label {
  position: absolute; left: -3rem; top: -.55rem;
  font-size: .7rem; color: #9aa2a8; font-variant-numeric: tabular-nums;
}
.track { position: absolute; inset: 0; }

.event {
  position: absolute; padding: .35rem .5rem;
  border-left: 3px solid var(--green); border-radius: 5px;
  background: #dbe9f7; overflow: hidden; font-size: .78rem; line-height: 1.3;
  /* A same-color inset "ring" around every block. Between two side-by-side columns
     that tile the rail edge-to-edge with no room to add a real margin (their
     left/width stay plain percentages -- see js/dayview.js), this is what reads as
     a gap: the later-painted (right-hand) column's ring draws over the seam in the
     page background color, since box-shadow is unaffected by this element's own
     overflow:hidden. Also gives every block a hairline of breathing room from the
     hour line above/below it. */
  box-shadow: 0 0 0 4px var(--bg);
}
.event.muted { background: #f1f3f5; border-left-style: dashed; border-left-color: #c3cad0; color: var(--muted); }
.event .time { font-variant-numeric: tabular-nums; color: var(--muted); font-size: .7rem; white-space: nowrap; }

/* Content-height bounding: every field below is clamped so a block's rendered
   height depends only on which fields are present, never on how long a name
   is or how narrow the column is (a 3rd overlapping event narrows the column
   to 33%, same as a 2nd narrows it to 50% -- both must stay bounded).
   The course name is the one clamp that visibly elides text, since it's the
   only field long enough to matter in the real data (see --hour-height
   derivation below); it keeps two lines because one line was too eager to
   truncate short/medium course names that fit fine at full width. Everything
   else clamps to a single line -- teacher lists, notes and room names are
   short enough in the real data that 1 line rarely elides anything, but the
   clamp still bounds the worst case a future longer value could bring. */
.event .course {
  font-weight: 700;
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 2;
  line-clamp: 2;
  overflow: hidden;
}
.event .activity, .event .teachers, .event .note {
  color: var(--muted); font-size: .72rem;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}

/* flex-wrap: nowrap (rather than wrap) keeps this to a single row no matter
   how many rooms an event has (seen up to 4 in the real data) or how narrow
   the column is -- extra chips overflow horizontally and are clipped by the
   parent .event's own overflow:hidden, instead of wrapping onto additional
   rows and growing the block's content height. */
.rooms { margin-top: .15rem; display: flex; flex-wrap: nowrap; overflow: hidden; gap: .4rem; }
a.room {
  color: var(--green); font-weight: 600; text-decoration: none; font-size: .74rem;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis; flex-shrink: 0;
}
a.room.unresolved { text-decoration: underline dotted; }
.room-tba { color: #9aa2a8; font-size: .74rem; font-style: italic; white-space: nowrap; }

/* All-day markers sit above the rail, not on it (js/dayview.js renderAllDay).
   Muted and time-less on purpose: a holiday is context for the day, not an
   appointment competing with the classes below it. */
.allday { margin: 0 0 .6rem; display: flex; flex-direction: column; gap: .3rem; }
.allday-item {
  background: #f1f3f5; color: var(--muted);
  border-left: 3px solid #c3cad0; border-radius: 5px;
  padding: .4rem .6rem; font-size: .8rem; font-weight: 600;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}

/* Passive, non-blocking: the day below it is real content, so this explains the
   date rather than replacing it (see js/app.js -- shown only when a request for
   *today* had to be clamped into the loaded range). */
.notice {
  margin: 0 0 .6rem; padding: .5rem .7rem;
  background: #fff6e0; border-left: 3px solid #e0a800; border-radius: 5px;
  color: #6b5a1f; font-size: .78rem; line-height: 1.35;
}
.notice[hidden] { display: none; }

.empty { color: var(--muted); text-align: center; padding: 3rem 0; }
.error { text-align: center; padding: 3rem 1rem; }
.error button {
  margin-top: 1rem; background: var(--green); color: #fff; border: 0;
  border-radius: 6px; padding: .6rem 1.2rem; font: inherit;
}
