/* ===========================================================================
   Design tokens. Every value the calendar draws with is defined here, once.

   The rule this file exists to enforce: a view never inlines a number. If a new
   view needs a value, it gets a token here first. Re-theming the wall panel --
   or making it readable for somebody whose eyes are worse than the owner's --
   has to be an edit to this file, not an expedition through eight templates.

   Layers, in order:
     1. faces      self-hosted Barlow; the CSP is `font-src 'self'`, so a webfont
                   CDN is not an option and a system stack cannot be trusted to
                   render the same on a Pi as on the laptop the design was drawn on
     2. palette    light theme, then the dark overrides
     3. lanes      the ten person colours, both themes, with their ink
     4. scale      type, space, radius, elevation, motion
     5. layout     the geometry the week grid is built from
     6. density    phone / kiosk-15 / kiosk-22 -- legibility, set as a class on <html>

   Density is a class, never a media query, because a 1920x1080 wall panel and a
   1920x1080 laptop are the same number of pixels and want completely different
   type sizes. Media queries below handle *reflow*; the density class handles
   *legibility*. `density-auto` is the only one that consults width, and it is the
   fallback for an ordinary browser rather than a target.
   =========================================================================== */

/* --- 1. faces ----------------------------------------------------------- */

/* Barlow, SIL Open Font License 1.1 (see static/fonts/OFL.txt). A low-contrast
   grotesque drawn for signage, which is what a wall calendar is. Two widths of
   one family rather than two families: the semi-condensed is not decoration, it
   is what makes a 264px day column hold a legible event title. Latin subset
   only -- the full set is four times the bytes for glyphs nothing renders. */

@font-face {
  font-family: "Barlow";
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url("../fonts/barlow-400.woff2") format("woff2");
}
@font-face {
  font-family: "Barlow";
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url("../fonts/barlow-500.woff2") format("woff2");
}
@font-face {
  font-family: "Barlow";
  font-style: normal;
  font-weight: 600;
  font-display: swap;
  src: url("../fonts/barlow-600.woff2") format("woff2");
}
@font-face {
  font-family: "Barlow";
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: url("../fonts/barlow-700.woff2") format("woff2");
}
@font-face {
  font-family: "Barlow Semi Condensed";
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url("../fonts/barlow-semi-condensed-500.woff2") format("woff2");
}
@font-face {
  font-family: "Barlow Semi Condensed";
  font-style: normal;
  font-weight: 600;
  font-display: swap;
  src: url("../fonts/barlow-semi-condensed-600.woff2") format("woff2");
}
@font-face {
  font-family: "Barlow Semi Condensed";
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: url("../fonts/barlow-semi-condensed-700.woff2") format("woff2");
}

/* --- 2. palette (light) -------------------------------------------------- */

:root {
  color-scheme: light;

  /* Cool paper rather than cream. A warm off-white under ten saturated lane
     colours turns the whole panel yellow at night; a neutral-cool ground keeps
     every hue reading as itself. */
  --bg: #e9ebee;
  --surface: #ffffff;
  --surface-sunk: #f2f4f6;
  --surface-inset: #dfe3e8;

  --ink: #14171b;
  --ink-muted: #5b636d;
  --ink-faint: #8d959f;
  --ink-inverse: #ffffff;

  --line: #d5d9de;
  --line-strong: #b6bcc4;
  --grid-line: #e4e7eb;
  --grid-line-major: #ccd2d8;

  /* Today is inverted, not tinted. A tint competes with ten lane colours and
     loses; a solid ink block cannot be mistaken for an event, in either theme,
     by anybody, from any distance. */
  --today-bg: #14171b;
  --today-ink: #ffffff;
  --today-column: #ffffff;

  /* The current-time line is ink, deliberately not a hue: every lane colour is
     already spoken for, and a line that shares a hue with a person reads as that
     person's event for the half second that matters. */
  --now-line: #14171b;
  /* The shadow at a scrollable edge. It is painted `background-attachment: scroll`
     under a cover painted `local`, so it is visible only when there is content past
     that edge -- a box you have to scroll is a box that said so, with no JavaScript
     and nothing to go stale. */
  --scroll-shade: #0000003d;

  --signal-warn: #a8321f;
  --signal-warn-bg: #fbe4e0;
  --focus: #14171b;


  /* Forms, links and status messages. These belong to the settings and auth pages
     rather than the calendar, but they are colours, and colours live here -- one
     palette for the whole product, not one per stylesheet. */
  --accent: #2f5d8c;
  --accent-ink: #ffffff;
  /* The Rewards tab, and nothing else (GOAL-30). One section is drawn in it, because
     one section spends where the other three report or record. */
  --section-accent: #6b3fa0;
  --section-accent-ink: #ffffff;
  --error-bg: #fbe4e0;
  --error-ink: #8c2f2f;
  --notice-bg: #e7f2ea;
  --notice-ink: #2f6b3a;
  --code-bg: #eef0f3;

  /* Google's sign-in button chrome, taken from their branding guidelines rather than
     chosen. https://developers.google.com/identity/branding-guidelines
  
     These are NOT ours to tune -- an OAuth verification reviewer checks them against
     the published values, and a well-meaning "make it match the accent" edit is a
     finding. They live in this file only because it is the one place the suite allows
     a hex code; Google publishes a light and a dark variant, so they are themed like
     everything else here. The logo itself is a file (`img/google-g.svg`) precisely so
     that no token can reach it. */
  --google-btn-bg: #ffffff;
  --google-btn-line: #747775;
  --google-btn-ink: #1f1f1f;

  --shadow-1: 0 1px 2px rgb(20 23 27 / 0.10);
  --shadow-2: 0 6px 18px rgb(20 23 27 / 0.14);
}

/* --- 2b. palette (dark) -------------------------------------------------- */

/* Defined twice on purpose: `prefers-color-scheme` for a browser that was told
   nothing, and `[data-theme]` for a kiosk that was. The attribute wins because it
   is later and more specific, which is what lets GOAL-09's per-device setting
   pin a panel to dark in a bright kitchen. */

@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    color-scheme: dark;

    --bg: #101317;
    --surface: #191d23;
    --surface-sunk: #14181d;
    --surface-inset: #262c34;

    --ink: #eef1f4;
    --ink-muted: #a2abb5;
    --ink-faint: #6e7883;
    --ink-inverse: #101317;

    --line: #2b323a;
    --line-strong: #3d454f;
    --grid-line: #232931;
    --grid-line-major: #333b44;

    --today-bg: #eef1f4;
    --today-ink: #101317;
    --today-column: #1f242b;

    --now-line: #eef1f4;
    --scroll-shade: #00000073;

    --signal-warn: #f2b5ab;
    --signal-warn-bg: #3d1c17;
    --focus: #eef1f4;


    --accent: #7aa8dd;
    --accent-ink: #101317;
    --section-accent: #b799e0;
    --section-accent-ink: #101317;
    --error-bg: #3d1c17;
    --error-ink: #f2b5ab;
    --notice-bg: #17301f;
    --notice-ink: #9ed9ae;
    --code-bg: #24282f;

    /* Google's sign-in button chrome, taken from their branding guidelines rather than
       chosen. https://developers.google.com/identity/branding-guidelines
    
       These are NOT ours to tune -- an OAuth verification reviewer checks them against
       the published values, and a well-meaning "make it match the accent" edit is a
       finding. They live in this file only because it is the one place the suite allows
       a hex code; Google publishes a light and a dark variant, so they are themed like
       everything else here. The logo itself is a file (`img/google-g.svg`) precisely so
       that no token can reach it. */
    --google-btn-bg: #131314;
    --google-btn-line: #8e918f;
    --google-btn-ink: #e3e3e3;

    --shadow-1: 0 1px 2px rgb(0 0 0 / 0.45);
    --shadow-2: 0 8px 22px rgb(0 0 0 / 0.55);
  }
}

[data-theme="dark"] {
  color-scheme: dark;

  --bg: #101317;
  --surface: #191d23;
  --surface-sunk: #14181d;
  --surface-inset: #262c34;

  --ink: #eef1f4;
  --ink-muted: #a2abb5;
  --ink-faint: #6e7883;
  --ink-inverse: #101317;

  --line: #2b323a;
  --line-strong: #3d454f;
  --grid-line: #232931;
  --grid-line-major: #333b44;

  --today-bg: #eef1f4;
  --today-ink: #101317;
  --today-column: #1f242b;

  --now-line: #eef1f4;
  --scroll-shade: #00000073;

  --signal-warn: #f2b5ab;
  --signal-warn-bg: #3d1c17;
  --focus: #eef1f4;


  --accent: #7aa8dd;
  --accent-ink: #101317;
  --section-accent: #b799e0;
  --section-accent-ink: #101317;
  --error-bg: #3d1c17;
  --error-ink: #f2b5ab;
  --notice-bg: #17301f;
  --notice-ink: #9ed9ae;
  --code-bg: #24282f;

  /* Google's sign-in button chrome, taken from their branding guidelines rather than
     chosen. https://developers.google.com/identity/branding-guidelines
  
     These are NOT ours to tune -- an OAuth verification reviewer checks them against
     the published values, and a well-meaning "make it match the accent" edit is a
     finding. They live in this file only because it is the one place the suite allows
     a hex code; Google publishes a light and a dark variant, so they are themed like
     everything else here. The logo itself is a file (`img/google-g.svg`) precisely so
     that no token can reach it. */
  --google-btn-bg: #131314;
  --google-btn-line: #8e918f;
  --google-btn-ink: #e3e3e3;

  --shadow-1: 0 1px 2px rgb(0 0 0 / 0.45);
  --shadow-2: 0 8px 22px rgb(0 0 0 / 0.55);
}

/* --- 3. lanes ------------------------------------------------------------ */

/* Ten hand-picked slots, matching the `color_token` values GOAL-03 stores
   (`app/palette.py`). Not generated by rotating hue: 360/10 produces two greens
   nobody can tell apart and a yellow that fails contrast, every time.

   Three properties are checked by `tests/test_design_tokens.py` rather than
   trusted, for both themes:
     - text on the fill clears WCAG AA (4.5:1), which is why the ink alternates
       between near-white and near-black per slot rather than being one value;
     - the fill is distinguishable from the surface it sits on;
     - *adjacent* slots differ in relative luminance by at least 0.15, which is
       what makes them survive a greyscale render and a squint from ten feet.

   The lightness deliberately alternates dark / light down the list, which is
   what buys that greyscale separation. Slots far apart in the list and both
   dark -- 03 and 07, say -- are not reliably separable in greyscale, and that is
   the honest limit of a ten-colour palette that also has to be vivid. It is why
   ADR-0008 makes the short name mandatory next to every appearance of a colour,
   and why no view here draws a colour on its own. */

:root {
  --lane-01: #2b5fd9; --lane-01-ink: #ffffff; /* cobalt   */
  --lane-02: #f2b01e; --lane-02-ink: #16191d; /* marigold */
  --lane-03: #0f7a63; --lane-03-ink: #ffffff; /* pine     */
  --lane-04: #f2789e; --lane-04-ink: #16191d; /* rose     */
  --lane-05: #8455c4; --lane-05-ink: #ffffff; /* violet   */
  --lane-06: #5bc6e8; --lane-06-ink: #16191d; /* sky      */
  --lane-07: #c4442e; --lane-07-ink: #ffffff; /* brick    */
  --lane-08: #a8ce3a; --lane-08-ink: #16191d; /* lime     */
  --lane-09: #42576b; --lane-09-ink: #ffffff; /* slate    */
  --lane-10: #f58a5b; --lane-10-ink: #16191d; /* apricot  */

  /* An event on a calendar nobody has been assigned to. Neutral on purpose: it
     is the one chip that is not claiming to be a person. */
  --lane-unassigned: #7b848e;
  --lane-unassigned-ink: #ffffff;
  /* A household that set a literal hex override chose the fill; this is the ink
     laid over it. Near-black reads on every colour a person is likely to pick
     for themselves, and a household that picks navy has picked badly on purpose. */
  --lane-override-ink: #14171b;
}

@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    /* Lifted and slightly desaturated: the light-theme values are tuned against
       white and go muddy on a dark ground, and a fully saturated fill on a wall
       panel at night is a lamp. Ink is near-black on every slot here, because at
       these luminances that is what clears AA. */
    --lane-01: #5c86ee; --lane-01-ink: #111419;
    --lane-02: #edb741; --lane-02-ink: #111419;
    --lane-03: #1f9377; --lane-03-ink: #111419;
    --lane-04: #f49bb8; --lane-04-ink: #111419;
    --lane-05: #9a6dd8; --lane-05-ink: #111419;
    --lane-06: #74d2f0; --lane-06-ink: #111419;
    --lane-07: #dc6048; --lane-07-ink: #111419;
    --lane-08: #badd55; --lane-08-ink: #111419;
    --lane-09: #788ea3; --lane-09-ink: #111419;
    --lane-10: #f8a87e; --lane-10-ink: #111419;

    --lane-unassigned: #8b95a0;
    --lane-unassigned-ink: #111419;
    --lane-override-ink: #14171b;
  }
}

[data-theme="dark"] {
  --lane-01: #5c86ee; --lane-01-ink: #111419;
  --lane-02: #edb741; --lane-02-ink: #111419;
  --lane-03: #1f9377; --lane-03-ink: #111419;
  --lane-04: #f49bb8; --lane-04-ink: #111419;
  --lane-05: #9a6dd8; --lane-05-ink: #111419;
  --lane-06: #74d2f0; --lane-06-ink: #111419;
  --lane-07: #dc6048; --lane-07-ink: #111419;
  --lane-08: #badd55; --lane-08-ink: #111419;
  --lane-09: #788ea3; --lane-09-ink: #111419;
  --lane-10: #f8a87e; --lane-10-ink: #111419;

  --lane-unassigned: #8b95a0;
  --lane-unassigned-ink: #111419;
  --lane-override-ink: #14171b;
}

/* --- 4. scale ------------------------------------------------------------ */

:root {
  --font-sans: "Barlow", ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
  --font-narrow: "Barlow Semi Condensed", "Barlow", ui-sans-serif, system-ui, sans-serif;
  --font-mono: ui-monospace, SFMono-Regular, Menlo, monospace;

  --fw-medium: 500;
  --fw-semi: 600;
  --fw-bold: 700;

  --lh-tight: 1.1;
  --lh-snug: 1.25;
  --lh-base: 1.5;

  --space-1: 0.25rem;
  --space-2: 0.5rem;
  --space-3: 0.75rem;
  --space-4: 1rem;
  --space-5: 1.25rem;
  --space-6: 1.5rem;
  --space-8: 3rem;

  --radius-xs: 3px;
  --radius-sm: 5px;
  --radius-md: 8px;
  --radius-lg: 14px;
  --radius-pill: 999px;

  --elev-1: var(--shadow-1);
  --elev-2: var(--shadow-2);

  --motion-fast: 120ms;
  --motion-base: 220ms;
  --ease: cubic-bezier(0.2, 0, 0, 1);
}

/* --- 5. layout ----------------------------------------------------------- */

:root {
  /* The display ceiling. Mirrored from `app.palette.DISPLAY_LANE_CEILING`, which
     is the one that decides behaviour; `tests/test_design_tokens.py` asserts the
     two agree, because a stylesheet cannot import Python.

     Six: a labelled all-day band row has to clear the 44px touch target and hold
     a readable name, which is 48px at kiosk density. Six rows is 288px of a
     1080-line panel and still leaves the time grid fourteen usable hours. A
     seventh starts eating the evening, which is the part of a family week
     anybody actually looks at. Above six the band changes shape rather than
     getting thinner -- see ADR-0013. */
  --lane-ceiling: 6;

  --touch-target: 44px;
  --gutter-width: 3.25rem;
  --band-row-height: 2rem;
  --hour-height: 3rem;
  /* Breathing room at the top and bottom of the time grid, so the first and last
     hour labels are not sliced in half by the edge of the card. Applied to the
     gutter and the columns equally -- see calendar.css. */
  --grid-inset: 0.7rem;
  --chip-gap: 2px;
  --chip-radius: var(--radius-sm);
  --rail-height: 2.25rem;
  --header-gap: var(--space-4);

  /* The month grid. A cell has to hold a date, the band rows that cross it and a
     few chips; below --month-cell-min it stops holding any of them legibly and the
     grid scrolls instead of shrinking. */
  --month-cell-min: 4.5rem;
  --month-band-row: 1.15rem;
  --month-entry-height: 1.2rem;

  /* The agenda's left column: wide enough for "9:30am - 10:45am" and no wider.
     The schedule view reuses it, so the two lists line their times up identically. */
  --agenda-when-width: 9.5rem;

  /* The People view. Six boxes have to fit a panel without it scrolling, so the box
     is whatever a sixth of the grid is -- but below --person-box-min it stops holding
     a name and a row legibly, and the grid scrolls rather than shrinking further. */
  --person-box-min: 6.5rem;
  --person-accent: 3px;

  /* The Checklist view (GOAL-21). `--check-row-height` is the one number that decides
     whether a six-year-old with imprecise aim can hit a row, so it is a token rather
     than a padding somewhere: at the kiosk densities it is well above the 44px that
     assumes an adult finger, and the 24" panel renders ~9% larger again than the
     figures here (CLAUDE.md, "Kiosk devices"). */
  --check-row-height: 2.75rem;
  --check-tick-size: 1.25rem;
  --check-accent: 3px;
  /* How far a ticked row recedes. Not `--past-opacity`: a done item is an achievement
     and should still be legible from across the room, where a past event is merely
     over. */
  --check-done-opacity: 0.62;

  /* The Chores view (GOAL-25). The rows are `--check-row-height` -- the same tap target
     decided for the same fingers -- so only what chores add gets tokens here.
     `--chore-chip-size` is the pool's own target: a chip is round and a child aims at
     its centre, so it is sized against the row height rather than against a font. */
  --chore-chip-size: 2.25rem;
  --fs-chore-points: 0.9rem;
  --fs-chore-state: 0.78rem;
  --fs-chore-balance: 1.05rem;

  /* The Rewards view (GOAL-30, ADR-0020). A tile is a tap target like every other one
     on this wall, so its height is `--check-row-height` doubled rather than a new
     number -- a tile carries a picture, a name and a price stacked, where a chore row
     carries them in a line.

     `--section-accent` is the one thing on the switcher that is not the shared "you are
     here" fill: exactly one section is drawn in it, because Rewards is the only tab that
     **spends** where the other three report or record. A token rather than a gap or a
     nudge to the right, for the reason every value on this wall is a token -- and
     because a separator is not something a finger reads at eight feet. */
  --reward-tile-height: calc(var(--check-row-height) * 2.5);
  --reward-tile-min: 14rem;
  /* And a **maximum**, which is the half that is easy to leave out. `auto-fill` with a
     bare `1fr` gave six tiles 157px each on a 1920 panel and left 570px of dead space to
     their right -- the tracks were exactly `--reward-tile-min` and the surplus went
     nowhere. Capping the track instead lets six rewards fill the width and twenty wrap,
     without a catalogue of two rendering as two 700px slabs. */
  --reward-tile-max: 26rem;
  /* The picture's own row. Fixed, so every card's name starts at the same height
     whether or not it has a picture -- see `.reward-art` in calendar.css. */
  --reward-art-size: 3.25rem;
  --fs-reward-name: 1.15rem;
  --fs-reward-cost: 1.6rem;
  --fs-reward-why: 0.78rem;
  /* **Deliberately not a lane colour.** A lane belongs to a person, and a tab wearing
     somebody's colour without their name is exactly what ADR-0008 section 3 forbids.
     This is its own hue, defined in all three theme blocks below like every other
     colour here. */

  /* How far an entry that has already happened recedes. It stays on the screen -- a
     list that empties itself over the day is indistinguishable from one that never
     had anything on it -- but it stops competing with what is still to come. */
  --past-opacity: 0.5;

  /* Night dimming, laid over the page as a veil. 0 by day; the server sets the
     night value, so a panel with a wrong clock still dims at the right moment. */
  --night-veil: #000814;

  /* Behind a `<dialog>`'s top layer: the chore picker, and anything modal after it.
     One value for both themes on purpose -- a backdrop's job is to say "the thing in
     front is the only thing", and a light-mode backdrop that is merely grey does not. */
  --scrim: #000814;
  --scrim-alpha: 0.55;

  /* Type, by role rather than by size. A view asks for `--fs-chip-title`; it
     never asks for 1.05rem, so the density classes below can move all of them at
     once and nothing is left behind. */
  --fs-micro: 0.72rem;
  --fs-xs: 0.8rem;
  --fs-sm: 0.9rem;
  --fs-base: 1rem;

  --fs-chip-title: 0.9rem;
  --fs-chip-time: 0.8rem;
  --fs-chip-name: 0.75rem;
  --fs-band-title: 0.85rem;
  --fs-lane-name: 0.8rem;
  --fs-hour: 0.78rem;
  --fs-day-name: 0.85rem;
  --fs-day-number: 1.5rem;
  --fs-clock: 1.75rem;
  --fs-range: 1.15rem;
  --fs-nav: 1rem;
  --fs-switch: 0.9rem;
  --fs-month-date: 0.85rem;
  --fs-month-entry: 0.78rem;
  --fs-agenda-when: 0.85rem;
  --fs-agenda-title: 1rem;
  --fs-person-name: 1rem;
  --fs-person-count: 0.78rem;
  --fs-person-when: 0.82rem;
  --fs-person-title: 0.92rem;
  --fs-check-item: 1rem;
  --fs-check-quiet: 0.82rem;
  --fs-check-party: 2rem;
}

/* --- 6. density ---------------------------------------------------------- */

/* `density-auto` is what an ordinary browser gets, and the only class that looks
   at width at all. The three explicit classes never do: a kiosk is a known
   physical object at a known distance, and guessing from its pixel count is how
   a 22" panel across the kitchen ends up typeset like a laptop on a desk. */

.density-auto {
  --fs-chip-title: 0.9rem;
  --fs-day-number: 1.5rem;
}

@media (max-width: 30rem) {
  .density-auto {
    --fs-chip-title: 0.95rem;
    --fs-chip-time: 0.85rem;
    --fs-day-number: 1.35rem;
    --fs-clock: 1.5rem;
    --hour-height: 3.25rem;
    --band-row-height: 2.1rem;
  }
}

.density-phone {
  --check-row-height: 3rem;
  --check-tick-size: 1.4rem;
  --chore-chip-size: 2.5rem;
  --fs-chore-points: 0.95rem;
  --fs-chore-state: 0.82rem;
  --fs-chore-balance: 1.1rem;
  --fs-check-item: 1.05rem;
  --fs-check-quiet: 0.88rem;
  --fs-check-party: 2.2rem;
  --fs-micro: 0.75rem;
  --fs-xs: 0.85rem;
  --fs-sm: 0.95rem;
  --fs-chip-title: 0.95rem;
  --fs-chip-time: 0.85rem;
  --fs-chip-name: 0.8rem;
  --fs-band-title: 0.9rem;
  --fs-lane-name: 0.85rem;
  --fs-hour: 0.8rem;
  --fs-day-name: 0.9rem;
  --fs-day-number: 1.4rem;
  --fs-clock: 1.5rem;
  --fs-range: 1.05rem;
  --gutter-width: 2.9rem;
  --hour-height: 3.25rem;
  --band-row-height: 2.15rem;
  --touch-target: 48px;
  --fs-switch: 0.95rem;
  --fs-month-date: 0.9rem;
  --fs-month-entry: 0.8rem;
  --fs-agenda-when: 0.9rem;
  --fs-agenda-title: 1.05rem;
  --fs-person-name: 1.05rem;
  --fs-person-count: 0.82rem;
  --fs-person-when: 0.85rem;
  --fs-person-title: 0.98rem;
  --month-cell-min: 3.6rem;
  --agenda-when-width: 8.5rem;
}

/* 15.6" at 1920x1080 is 5.6 physical pixels per millimetre against the 22"
   panel's 3.9, so the *same* type is 30% smaller on the glass. It is also the
   panel somebody stands closer to. Both effects point the same way: more pixels
   per glyph, not fewer. */
.density-kiosk-15 {
  --check-row-height: 3.4rem;
  --check-tick-size: 1.6rem;
  --fs-check-item: 1.28rem;
  --fs-check-quiet: 1rem;
  --fs-check-party: 3rem;
  --fs-micro: 0.95rem;
  --fs-xs: 1.05rem;
  --fs-sm: 1.15rem;
  --fs-base: 1.25rem;
  --fs-chip-title: 1.28rem;
  --fs-chip-time: 1.1rem;
  --fs-chip-name: 1.02rem;
  --fs-band-title: 1.18rem;
  --fs-lane-name: 1.1rem;
  --fs-hour: 1.05rem;
  --fs-day-name: 1.15rem;
  --fs-day-number: 2.6rem;
  --fs-clock: 2.6rem;
  --fs-range: 1.65rem;
  --fs-nav: 1.3rem;
  --gutter-width: 5.2rem;
  --band-row-height: 2.7rem;
  --hour-height: 4.1rem;
  --rail-height: 3rem;
  --touch-target: 56px;
  --chip-gap: 3px;
  --fs-switch: 1.2rem;
  --fs-month-date: 1.15rem;
  --fs-month-entry: 1.02rem;
  --fs-agenda-when: 1.15rem;
  --fs-agenda-title: 1.35rem;
  --fs-person-name: 1.35rem;
  --fs-person-count: 1.02rem;
  --fs-person-when: 1.1rem;
  --fs-person-title: 1.28rem;
  --month-band-row: 1.6rem;
  --month-entry-height: 1.6rem;
  --agenda-when-width: 12rem;
  --person-box-min: 9.5rem;
  --person-accent: 4px;
  /* Kept level with --person-accent. The Checklist family was copied from the
     People family, and this density bumped one and not the other. */
  --check-accent: 4px;
  --chore-chip-size: 2.9rem;
  --fs-chore-points: 1.12rem;
  --fs-chore-state: 0.96rem;
  --fs-chore-balance: 1.3rem;
}

.density-kiosk-22 {
  /* 4rem is 64px at the panel's root size -- the measured tap target, chosen for a
     child's aim rather than for the 44px minimum, which assumes an adult. */
  --check-row-height: 4rem;
  --check-tick-size: 1.8rem;
  --check-accent: 4px;
  /* 3.25rem is 52px at the panel's root size. Bigger than the 44px adult minimum for
     the same reason `--check-row-height` is: this is aimed at by a six-year-old. */
  --chore-chip-size: 3.25rem;
  --fs-chore-points: 1.25rem;
  --fs-chore-state: 1.05rem;
  --fs-chore-balance: 1.5rem;
  --fs-check-item: 1.42rem;
  --fs-check-quiet: 1.08rem;
  --fs-check-party: 3.6rem;
  --fs-micro: 0.85rem;
  --fs-xs: 0.95rem;
  --fs-sm: 1.05rem;
  --fs-base: 1.15rem;
  --fs-chip-title: 1.18rem;
  --fs-chip-time: 1rem;
  --fs-chip-name: 0.95rem;
  --fs-band-title: 1.1rem;
  --fs-lane-name: 1.02rem;
  --fs-hour: 0.98rem;
  --fs-day-name: 1.08rem;
  --fs-day-number: 2.4rem;
  --fs-clock: 2.4rem;
  --fs-range: 1.5rem;
  --fs-nav: 1.2rem;
  --gutter-width: 4.8rem;
  --band-row-height: 2.5rem;
  --hour-height: 3.8rem;
  --rail-height: 2.8rem;
  --touch-target: 48px;
  --chip-gap: 3px;
  --fs-switch: 1.1rem;
  --fs-month-date: 1.05rem;
  --fs-month-entry: 0.95rem;
  --fs-agenda-when: 1.05rem;
  --fs-agenda-title: 1.25rem;
  --fs-person-name: 1.25rem;
  --fs-person-count: 0.95rem;
  --fs-person-when: 1.02rem;
  --fs-person-title: 1.18rem;
  --month-band-row: 1.5rem;
  --month-entry-height: 1.5rem;
  --agenda-when-width: 11rem;
  --person-box-min: 8.5rem;
  --person-accent: 4px;
}

/* A wall panel is a fixed object: it never scrolls, and nothing on it may depend
   on hovering, because there is no pointer. */
.density-kiosk-15,
.density-kiosk-22 {
  cursor: none;
}

@media (prefers-reduced-motion: reduce) {
  :root {
    --motion-fast: 0ms;
    --motion-base: 0ms;
  }
}
