/* Chores — design system.
   Built mobile-first: the layout below is an app shell (a sticky app bar, a
   fixed bottom tab bar, a scrolling content area between them) that widens
   into an ordinary centred page on a desktop viewport, rather than a desktop
   page that merely reflows. */

:root {
  color-scheme: light dark;

  --bg: #f2f3f7;
  --surface: #ffffff;
  --card: #ffffff;
  --surface-sunken: #eceef4;
  --text: #11141a;
  --muted: #656d7b;
  --faint: #98a0ae;
  --border: #e5e8ef;
  --border-strong: #d3d8e2;

  --accent: #2563eb;
  --accent-hover: #1d4ed8;
  --accent-soft: #e7efff;
  --accent-fg: #ffffff;
  --green: #16a34a;
  --green-soft: #dcfce7;
  --red: #dc2626;
  --red-soft: #fee2e2;
  --red-text: #991b1b;

  --shadow-sm: 0 1px 2px rgba(16, 24, 40, 0.05), 0 1px 3px rgba(16, 24, 40, 0.04);
  --shadow-md: 0 4px 16px rgba(16, 24, 40, 0.09);
  --shadow-lg: 0 16px 48px rgba(16, 24, 40, 0.24);

  --r-xl: 22px;
  --r-lg: 16px;
  --r-md: 12px;
  --r-sm: 10px;

  /* Pill background/foreground pairs, broken out as tokens (rather than
     hardcoded on the .pill.* rules below) so a theme can restyle them too —
     see the retro/playful blocks further down. */
  --pill-parent-bg: #dbeafe;
  --pill-parent-fg: #1e40af;
  --pill-child-bg: #dcfce7;
  --pill-child-fg: #166534;
  --pill-notcompleted-bg: #fee2e2;
  --pill-notcompleted-fg: #991b1b;
  --pill-mandatory-bg: #fef3c7;
  --pill-mandatory-fg: #92400e;
  --pill-optional-bg: #e0e7ff;
  --pill-optional-fg: #3730a3;

  /* A repeating decorative background tile, off by default — playful and
     space-invaders set it. Read by the body rule below; kept as a token
     rather than a per-theme body selector so themes without one don't need
     to say so. */
  --bg-pattern: none;

  --page: 860px;
  --gutter: 16px;
  --tabbar-h: 58px;
  /* env() falls back to 0px on browsers without a notch/home indicator, so
     these are safe to add unconditionally. */
  --safe-t: env(safe-area-inset-top, 0px);
  --safe-b: env(safe-area-inset-bottom, 0px);
  --safe-l: env(safe-area-inset-left, 0px);
  --safe-r: env(safe-area-inset-right, 0px);

  font-family: -apple-system, BlinkMacSystemFont, system-ui, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
  font-size: 16px;
}

/* Settings offers an explicit Light/Dark/Retro/Playful/Space Invaders/High
   Contrast choice on top of the OS-following default ("Match device"). An
   explicit choice is stamped as
   data-theme on <html> by applyTheme() in app.js (and, before that file
   even loads, by a standalone copy in index.html/login.html's <head> —
   see the comment there). The system-dark block below is scoped to
   :not([data-theme]) so it only fires for "Match device"; each explicit
   theme gets its own block, guarded by the attribute, further down. */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme]) {
    --bg: #101216;
    --surface: #1a1d23;
    --card: #1a1d23;
    --surface-sunken: #23272f;
    --text: #e8eaee;
    --muted: #9aa2b0;
    --faint: #767e8c;
    --border: #2a2f38;
    --border-strong: #3a4049;

    --accent: #3b82f6;
    --accent-hover: #60a5fa;
    --accent-soft: #1e3a8a55;
    --green: #22c55e;
    --green-soft: #14532d55;
    --red: #ef4444;
    --red-soft: #7f1d1d55;
    --red-text: #fca5a5;

    --shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.4);
    --shadow-md: 0 4px 16px rgba(0, 0, 0, 0.45);
    --shadow-lg: 0 16px 48px rgba(0, 0, 0, 0.6);

    --pill-parent-bg: #1e3a8a55;
    --pill-parent-fg: #93c5fd;
    --pill-child-bg: #14532d55;
    --pill-child-fg: #86efac;
    --pill-notcompleted-bg: #7f1d1d55;
    --pill-notcompleted-fg: #fca5a5;
    --pill-mandatory-bg: #92400e55;
    --pill-mandatory-fg: #fcd34d;
    --pill-optional-bg: #3730a355;
    --pill-optional-fg: #a5b4fc;

    color-scheme: dark;
  }
}

/* data-theme="light" needs no block of its own: the bare :root above is
   already the light palette, and :not([data-theme]) on the system-dark
   block already keeps it from applying once any explicit theme is picked.
   This still needs to force color-scheme so native controls (scrollbars,
   checkboxes) read as light even when the OS itself is set to dark. */
:root[data-theme="light"] {
  color-scheme: light;
}

:root[data-theme="dark"] {
  --bg: #101216;
  --surface: #1a1d23;
  --card: #1a1d23;
  --surface-sunken: #23272f;
  --text: #e8eaee;
  --muted: #9aa2b0;
  --faint: #767e8c;
  --border: #2a2f38;
  --border-strong: #3a4049;

  --accent: #3b82f6;
  --accent-hover: #60a5fa;
  --accent-soft: #1e3a8a55;
  --green: #22c55e;
  --green-soft: #14532d55;
  --red: #ef4444;
  --red-soft: #7f1d1d55;
  --red-text: #fca5a5;

  --shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.4);
  --shadow-md: 0 4px 16px rgba(0, 0, 0, 0.45);
  --shadow-lg: 0 16px 48px rgba(0, 0, 0, 0.6);

  --pill-parent-bg: #1e3a8a55;
  --pill-parent-fg: #93c5fd;
  --pill-child-bg: #14532d55;
  --pill-child-fg: #86efac;
  --pill-notcompleted-bg: #7f1d1d55;
  --pill-notcompleted-fg: #fca5a5;
  --pill-mandatory-bg: #92400e55;
  --pill-mandatory-fg: #fcd34d;
  --pill-optional-bg: #3730a355;
  --pill-optional-fg: #a5b4fc;

  color-scheme: dark;
}

/* Warm and boxy rather than the app's usual cool neutrals — a sepia paper
   background, a serif face, and slightly squared-off corners. */
:root[data-theme="retro"] {
  --bg: #f1e6d2;
  --surface: #fbf3e3;
  --card: #fbf3e3;
  --surface-sunken: #e9dcc0;
  --text: #3a2e22;
  --muted: #7a6a53;
  --faint: #a3927a;
  --border: #d8c7a3;
  --border-strong: #c2ac7d;

  --accent: #b5541f;
  --accent-hover: #9c4517;
  --accent-soft: #f0d3ba;
  --accent-fg: #fff8ef;
  --green: #5c7a35;
  --green-soft: #dbe6c0;
  --red: #a13a2d;
  --red-soft: #f0d2ca;
  --red-text: #7a2b21;

  --shadow-sm: 0 1px 2px rgba(58, 46, 34, 0.12), 0 1px 3px rgba(58, 46, 34, 0.1);
  --shadow-md: 0 4px 16px rgba(58, 46, 34, 0.18);
  --shadow-lg: 0 16px 48px rgba(58, 46, 34, 0.32);

  --r-xl: 14px;
  --r-lg: 10px;
  --r-md: 8px;
  --r-sm: 6px;

  --pill-parent-bg: #e9d1a0;
  --pill-parent-fg: #6b4a1e;
  --pill-child-bg: #d7e0b0;
  --pill-child-fg: #435415;
  --pill-notcompleted-bg: #e8c2b0;
  --pill-notcompleted-fg: #7a2b21;
  --pill-mandatory-bg: #f0d3a0;
  --pill-mandatory-fg: #7a4e12;
  --pill-optional-bg: #d9cba0;
  --pill-optional-fg: #55461c;

  color-scheme: light;
  font-family: Georgia, "Times New Roman", Times, serif;
}

/* Bright and bubbly — candy-pink surfaces, a bigger radius everywhere, and
   a rounded display face instead of the app's usual system sans. */
:root[data-theme="playful"] {
  --bg: #fdf1fb;
  --surface: #ffffff;
  --card: #ffffff;
  --surface-sunken: #f6e8fb;
  --text: #2d1b3a;
  --muted: #8a7398;
  --faint: #b39fc0;
  --border: #ecd6f2;
  --border-strong: #ddb8ea;

  --accent: #ff5da2;
  --accent-hover: #ff3d8f;
  --accent-soft: #ffe0ef;
  --accent-fg: #ffffff;
  --green: #12b76a;
  --green-soft: #d3f8df;
  --red: #fb4d3d;
  --red-soft: #ffe1db;
  --red-text: #b5321f;

  --shadow-sm: 0 1px 2px rgba(214, 51, 108, 0.1), 0 1px 3px rgba(214, 51, 108, 0.08);
  --shadow-md: 0 4px 16px rgba(214, 51, 108, 0.16);
  --shadow-lg: 0 16px 48px rgba(214, 51, 108, 0.28);

  --r-xl: 28px;
  --r-lg: 22px;
  --r-md: 16px;
  --r-sm: 12px;

  --pill-parent-bg: #dbe4ff;
  --pill-parent-fg: #3730a3;
  --pill-child-bg: #d3f8df;
  --pill-child-fg: #0f7a42;
  --pill-notcompleted-bg: #ffe1db;
  --pill-notcompleted-fg: #b5321f;
  --pill-mandatory-bg: #fff3c4;
  --pill-mandatory-fg: #92600a;
  --pill-optional-bg: #ffe0ef;
  --pill-optional-fg: #a3195b;

  color-scheme: light;
  font-family: "Comic Sans MS", "Chalkboard SE", "Trebuchet MS", sans-serif;

  /* A repeating teddy bear, heart, star and balloon tile, tinted just
     above the surface color — see --bg-pattern's definition above. Cards
     stay opaque, so this only actually shows in the gaps between them and
     faintly through the translucent app bar/tab bar, not behind text. */
  --bg-pattern: url("data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20width='160'%20height='160'%20viewBox='0%200%20160%20160'%3E%3Cg%20fill='%23ffb8de'%20opacity='0.55'%3E%3Ccircle%20cx='40'%20cy='42'%20r='14'/%3E%3Ccircle%20cx='29'%20cy='27'%20r='5'/%3E%3Ccircle%20cx='51'%20cy='27'%20r='5'/%3E%3Cellipse%20cx='40'%20cy='48'%20rx='4'%20ry='3'/%3E%3Cg%20transform='translate(98,8)%20scale(1.3)'%3E%3Cpath%20d='M12%2021s-8-4.5-8-11a5%205%200%200%201%208-4%205%205%200%200%201%208%204c0%206.5-8%2011-8%2011z'/%3E%3C/g%3E%3Cg%20transform='translate(6,90)%20scale(1.15)'%3E%3Cpath%20d='M12%202l2.9%206.9L22%209.3l-5.5%204.8L18.2%2022%2012%2018.3%205.8%2022l1.7-7.9L2%209.3l7.1-.4z'/%3E%3C/g%3E%3Cellipse%20cx='128'%20cy='112'%20rx='9'%20ry='12'/%3E%3Cpath%20d='M128%20124l-2%206h4z'/%3E%3C/g%3E%3C/svg%3E");
}

/* A CRT terminal: near-black surfaces, green-on-black text, square corners,
   and a monospace face everywhere — the same green as .terminal-cmd's
   fixed, theme-independent look above, so the grpcurl example on the API
   access page reads as "at home" here instead of standing out. */
:root[data-theme="hacker"] {
  --bg: #0a0e0a;
  --surface: #0d1410;
  --card: #0d1410;
  --surface-sunken: #0f1a12;
  --text: #3ddc4a;
  --muted: #4a7a52;
  --faint: #2f5a38;
  --border: #1c3320;
  --border-strong: #2a4a30;

  --accent: #00ff41;
  --accent-hover: #33ff66;
  --accent-soft: #103a1a;
  --accent-fg: #04140a;
  --green: #00ff41;
  --green-soft: #0d2a12;
  --red: #ff3b3b;
  --red-soft: #2a1010;
  --red-text: #ff6b6b;

  --shadow-sm: 0 0 0 1px rgba(61, 220, 74, 0.08), 0 1px 2px rgba(0, 0, 0, 0.6);
  --shadow-md: 0 0 16px rgba(61, 220, 74, 0.12), 0 4px 16px rgba(0, 0, 0, 0.6);
  --shadow-lg: 0 0 32px rgba(61, 220, 74, 0.18), 0 16px 48px rgba(0, 0, 0, 0.7);

  --r-xl: 4px;
  --r-lg: 3px;
  --r-md: 2px;
  --r-sm: 2px;

  --pill-parent-bg: #10241a;
  --pill-parent-fg: #3ddc4a;
  --pill-child-bg: #142a18;
  --pill-child-fg: #5eff7e;
  --pill-notcompleted-bg: #2a1010;
  --pill-notcompleted-fg: #ff5f5f;
  --pill-mandatory-bg: #241f10;
  --pill-mandatory-fg: #e2d24a;
  --pill-optional-bg: #10241f;
  --pill-optional-fg: #4adec2;

  color-scheme: dark;
  font-family: ui-monospace, "SFMono-Regular", Consolas, "Liberation Mono", Menlo, monospace;
}

/* An arcade cabinet: black surfaces, a cyan/magenta/invader-green palette
   distinct from hacker's uniform green-on-black, zero radius (pixel-art
   square edges, more literal than hacker's slightly-rounded "CRT" look),
   and hard-edged offset shadows instead of soft blur. */
:root[data-theme="space-invaders"] {
  --bg: #000000;
  --surface: #0a0a12;
  --card: #0a0a12;
  --surface-sunken: #12121e;
  --text: #e8e8f0;
  --muted: #8888a8;
  --faint: #55557a;
  --border: #22223a;
  --border-strong: #33335a;

  --accent: #00e5ff;
  --accent-hover: #33ecff;
  --accent-soft: #0a2a30;
  --accent-fg: #001014;
  --green: #39ff14;
  --green-soft: #0d2a08;
  --red: #ff2e4d;
  --red-soft: #2a0a10;
  --red-text: #ff6b81;

  --shadow-sm: 2px 2px 0 rgba(0, 229, 255, 0.15);
  --shadow-md: 3px 3px 0 rgba(0, 229, 255, 0.2);
  --shadow-lg: 4px 4px 0 rgba(0, 229, 255, 0.25);

  --r-xl: 0;
  --r-lg: 0;
  --r-md: 0;
  --r-sm: 0;

  --pill-parent-bg: #0a2a30;
  --pill-parent-fg: #00e5ff;
  --pill-child-bg: #0d2a08;
  --pill-child-fg: #39ff14;
  --pill-notcompleted-bg: #2a0a10;
  --pill-notcompleted-fg: #ff6b81;
  --pill-mandatory-bg: #2a2408;
  --pill-mandatory-fg: #ffe14d;
  --pill-optional-bg: #1a0a2a;
  --pill-optional-fg: #cc7aff;

  color-scheme: dark;
  font-family: ui-monospace, "SFMono-Regular", Consolas, "Liberation Mono", Menlo, monospace;

  /* One pixel-grid alien, repeated — the same idea as playful's tile
     above, just a single blocky path instead of rects/curves to keep the
     data URI shorter. */
  --bg-pattern: url("data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20width='100'%20height='100'%20viewBox='0%200%20100%20100'%3E%3Cpath%20transform='translate(17,26)'%20fill='%2339ff14'%20opacity='0.3'%20d='M12%200%20h6%20v6%20h-6%20ZM48%200%20h6%20v6%20h-6%20ZM18%206%20h6%20v6%20h-6%20ZM42%206%20h6%20v6%20h-6%20ZM12%2012%20h6%20v6%20h-6%20ZM18%2012%20h6%20v6%20h-6%20ZM24%2012%20h6%20v6%20h-6%20ZM30%2012%20h6%20v6%20h-6%20ZM36%2012%20h6%20v6%20h-6%20ZM42%2012%20h6%20v6%20h-6%20ZM48%2012%20h6%20v6%20h-6%20ZM6%2018%20h6%20v6%20h-6%20ZM12%2018%20h6%20v6%20h-6%20ZM24%2018%20h6%20v6%20h-6%20ZM30%2018%20h6%20v6%20h-6%20ZM36%2018%20h6%20v6%20h-6%20ZM48%2018%20h6%20v6%20h-6%20ZM54%2018%20h6%20v6%20h-6%20ZM0%2024%20h6%20v6%20h-6%20ZM6%2024%20h6%20v6%20h-6%20ZM12%2024%20h6%20v6%20h-6%20ZM18%2024%20h6%20v6%20h-6%20ZM24%2024%20h6%20v6%20h-6%20ZM30%2024%20h6%20v6%20h-6%20ZM36%2024%20h6%20v6%20h-6%20ZM42%2024%20h6%20v6%20h-6%20ZM48%2024%20h6%20v6%20h-6%20ZM54%2024%20h6%20v6%20h-6%20ZM60%2024%20h6%20v6%20h-6%20ZM0%2030%20h6%20v6%20h-6%20ZM12%2030%20h6%20v6%20h-6%20ZM18%2030%20h6%20v6%20h-6%20ZM24%2030%20h6%20v6%20h-6%20ZM30%2030%20h6%20v6%20h-6%20ZM36%2030%20h6%20v6%20h-6%20ZM42%2030%20h6%20v6%20h-6%20ZM48%2030%20h6%20v6%20h-6%20ZM60%2030%20h6%20v6%20h-6%20ZM0%2036%20h6%20v6%20h-6%20ZM12%2036%20h6%20v6%20h-6%20ZM48%2036%20h6%20v6%20h-6%20ZM60%2036%20h6%20v6%20h-6%20ZM18%2042%20h6%20v6%20h-6%20ZM24%2042%20h6%20v6%20h-6%20ZM36%2042%20h6%20v6%20h-6%20ZM42%2042%20h6%20v6%20h-6%20Z'/%3E%3C/svg%3E");
}

/* Maximum legibility: pure black text on white, black borders throughout
   (border and border-strong collapse to the same value), and darkened
   semantic colors chosen to keep strong contrast against white rather
   than the app's usual soft pastel accents. No background pattern and no
   radius/font override — this theme is about contrast, not decoration. */
:root[data-theme="high-contrast"] {
  --bg: #ffffff;
  --surface: #ffffff;
  --card: #ffffff;
  --surface-sunken: #e8e8e8;
  --text: #000000;
  --muted: #3a3a3a;
  --faint: #545454;
  --border: #000000;
  --border-strong: #000000;

  --accent: #0033cc;
  --accent-hover: #002299;
  --accent-soft: #cce0ff;
  --accent-fg: #ffffff;
  --green: #006400;
  --green-soft: #d6f5d6;
  --red: #b30000;
  --red-soft: #ffd6d6;
  --red-text: #7a0000;

  --shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.3);
  --shadow-md: 0 2px 6px rgba(0, 0, 0, 0.35);
  --shadow-lg: 0 6px 16px rgba(0, 0, 0, 0.4);

  --pill-parent-bg: #cce0ff;
  --pill-parent-fg: #001a4d;
  --pill-child-bg: #d6f5d6;
  --pill-child-fg: #003300;
  --pill-notcompleted-bg: #ffd6d6;
  --pill-notcompleted-fg: #4d0000;
  --pill-mandatory-bg: #fff0b3;
  --pill-mandatory-fg: #4d3800;
  --pill-optional-bg: #e6d6ff;
  --pill-optional-fg: #2e004d;

  color-scheme: light;
}

/* A friendly forest clearing: moss green, bark brown, and a muted-gold
   accent standing in for a sunlit path. Kept soft rather than saturated so
   it reads calm as easily as cheerful — the brief for this one covers both
   a kids' profile and a quieter adult read off the same palette. */
:root[data-theme="fairytale-forest"] {
  --bg: #f3efdf;
  --surface: #fffdf5;
  --card: #fffdf5;
  --surface-sunken: #e8e0c4;
  --text: #2b3a22;
  --muted: #6f7a5c;
  --faint: #9aa385;
  --border: #ddd2ad;
  --border-strong: #c7b98c;

  --accent: #b5862a;
  --accent-hover: #996f1f;
  --accent-soft: #f3e6c2;
  --accent-fg: #2b2308;
  --green: #4c7a3a;
  --green-soft: #dcead0;
  --red: #b5482e;
  --red-soft: #f3ddd0;
  --red-text: #7a3220;

  --shadow-sm: 0 1px 2px rgba(43, 58, 34, 0.1), 0 1px 3px rgba(43, 58, 34, 0.08);
  --shadow-md: 0 4px 16px rgba(43, 58, 34, 0.16);
  --shadow-lg: 0 16px 48px rgba(43, 58, 34, 0.26);

  --r-xl: 24px;
  --r-lg: 18px;
  --r-md: 14px;
  --r-sm: 10px;

  --pill-parent-bg: #e4d9b0;
  --pill-parent-fg: #5b4a1e;
  --pill-child-bg: #dcead0;
  --pill-child-fg: #2f5c1e;
  --pill-notcompleted-bg: #f3ddd0;
  --pill-notcompleted-fg: #7a3220;
  --pill-mandatory-bg: #f5e6b0;
  --pill-mandatory-fg: #7a5e12;
  --pill-optional-bg: #d7e6e0;
  --pill-optional-fg: #1f5c50;

  color-scheme: light;
  font-family: "Trebuchet MS", Verdana, sans-serif;

  /* A little pine, a star and a fallen leaf, repeated — see --bg-pattern's
     definition near the top of this file. */
  --bg-pattern: url("data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20width='140'%20height='140'%20viewBox='0%200%20140%20140'%3E%3Cg%20fill='%234c7a3a'%20opacity='0.35'%3E%3Cpath%20d='M20%2010%20L30%2030%20L10%2030%20Z'/%3E%3Cpath%20d='M20%2020%20L33%2045%20L7%2045%20Z'/%3E%3Cpath%20d='M20%2034%20L36%2062%20L4%2062%20Z'/%3E%3Crect%20x='17'%20y='62'%20width='6'%20height='10'/%3E%3Cpath%20d='M100%2020%20l3%207%207%201%20-5%205%201%207%20-6%20-3%20-6%203%201%20-7%20-5%20-5%207%20-1%20Z'/%3E%3Cellipse%20cx='95'%20cy='95'%20rx='10'%20ry='5'%20transform='rotate(30%2095%2095)'/%3E%3C/g%3E%3C/svg%3E");
}

/* Sun-bleached parchment: sand and dark ink, a sea-blue accent for the
   primary action, and gold reserved for "must-do" — a task feels like a
   marked treasure rather than just another button. */
:root[data-theme="pirate-map"] {
  --bg: #ecd9ad;
  --surface: #f7ecd1;
  --card: #f7ecd1;
  --surface-sunken: #e0c78e;
  --text: #3b2a17;
  --muted: #7a6540;
  --faint: #a68f61;
  --border: #d2b57e;
  --border-strong: #b89a5e;

  --accent: #a5761a;
  --accent-hover: #8c6215;
  --accent-soft: #f0dba0;
  --accent-fg: #2b1e05;
  --green: #4f7a3a;
  --green-soft: #dde6c4;
  --red: #9c3b26;
  --red-soft: #ecd0c2;
  --red-text: #6b2717;

  --shadow-sm: 0 1px 2px rgba(59, 42, 23, 0.14), 0 1px 3px rgba(59, 42, 23, 0.1);
  --shadow-md: 0 4px 16px rgba(59, 42, 23, 0.2);
  --shadow-lg: 0 16px 48px rgba(59, 42, 23, 0.32);

  --r-xl: 12px;
  --r-lg: 9px;
  --r-md: 7px;
  --r-sm: 5px;

  --pill-parent-bg: #cfe6ee;
  --pill-parent-fg: #123a4a;
  --pill-child-bg: #dde6c4;
  --pill-child-fg: #3c4f1e;
  --pill-notcompleted-bg: #ecd0c2;
  --pill-notcompleted-fg: #6b2717;
  --pill-mandatory-bg: #f0dba0;
  --pill-mandatory-fg: #7a5b12;
  --pill-optional-bg: #e6d6ee;
  --pill-optional-fg: #4a2f6b;

  color-scheme: light;
  font-family: "Palatino Linotype", "Book Antiqua", Georgia, serif;

  /* A compass rose, an X, and a dotted route — a map, not a specific one. */
  --bg-pattern: url("data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20width='140'%20height='140'%20viewBox='0%200%20140%20140'%3E%3Cg%20fill='%237a5b2a'%20opacity='0.35'%3E%3Cpath%20d='M30%206%20L34%2026%20L54%2030%20L34%2034%20L30%2054%20L26%2034%20L6%2030%20L26%2026%20Z'/%3E%3Cpath%20d='M95%2085%20l8%208%20-3%203%20-8%20-8%20-8%208%20-3%20-3%208%20-8%20-8%20-8%203%20-3%208%208%208%20-8%203%203%20Z'/%3E%3Ccircle%20cx='100'%20cy='30'%20r='2'/%3E%3Ccircle%20cx='108'%20cy='36'%20r='2'/%3E%3Ccircle%20cx='116'%20cy='44'%20r='2'/%3E%3C/g%3E%3C/svg%3E");
}

/* Sea-green and turquoise on a pearl-white surface, with a soft coral for
   alerts instead of the app's usual hard red — the one concession here to
   "soft movement" a static palette can make. */
:root[data-theme="underwater"] {
  --bg: #eaf6f6;
  --surface: #ffffff;
  --card: #ffffff;
  --surface-sunken: #d9f0ee;
  --text: #0d3b3f;
  --muted: #4c7a80;
  --faint: #86aeb2;
  --border: #cdeae8;
  --border-strong: #a9dbd8;

  --accent: #0e8f8f;
  --accent-hover: #0b7373;
  --accent-soft: #d3f3f0;
  --accent-fg: #ffffff;
  --green: #1fa66b;
  --green-soft: #d3f5e4;
  --red: #d64545;
  --red-soft: #fbdada;
  --red-text: #8a2626;

  --shadow-sm: 0 1px 2px rgba(13, 59, 63, 0.1), 0 1px 3px rgba(13, 59, 63, 0.08);
  --shadow-md: 0 4px 16px rgba(13, 59, 63, 0.16);
  --shadow-lg: 0 16px 48px rgba(13, 59, 63, 0.26);

  --r-xl: 26px;
  --r-lg: 20px;
  --r-md: 16px;
  --r-sm: 12px;

  --pill-parent-bg: #cfeaf7;
  --pill-parent-fg: #0b4a63;
  --pill-child-bg: #d3f5e4;
  --pill-child-fg: #106b43;
  --pill-notcompleted-bg: #fbdada;
  --pill-notcompleted-fg: #8a2626;
  --pill-mandatory-bg: #fdf0c2;
  --pill-mandatory-fg: #7a5e12;
  --pill-optional-bg: #e6def7;
  --pill-optional-fg: #4a2f8a;

  color-scheme: light;

  /* A fish, a trail of bubbles and a strand of seaweed. */
  --bg-pattern: url("data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20width='150'%20height='150'%20viewBox='0%200%20150%20150'%3E%3Cg%20fill='%230e8f8f'%20opacity='0.3'%3E%3Cellipse%20cx='30'%20cy='30'%20rx='16'%20ry='9'/%3E%3Cpath%20d='M14%2030%20L2%2022%20L2%2038%20Z'/%3E%3Ccircle%20cx='38'%20cy='27'%20r='1.6'%20fill='%23ffffff'/%3E%3Ccircle%20cx='110'%20cy='100'%20r='5'/%3E%3Ccircle%20cx='122'%20cy='112'%20r='3.5'/%3E%3Ccircle%20cx='104'%20cy='115'%20r='2.5'/%3E%3Cpath%20d='M90%2040%20q6%208%200%2016%20q-6%208%200%2016'%20stroke='%230e8f8f'%20stroke-width='3'%20fill='none'/%3E%3C/g%3E%3C/svg%3E");
}

/* A dark workshop bench rather than a bright one — graphite surfaces, a
   cyan primary, and orange reserved for "must-do" the way a warning light
   is orange on real equipment. A task here reads as a small job ticket. */
:root[data-theme="robot-workshop"] {
  --bg: #1c1f22;
  --surface: #24282c;
  --card: #24282c;
  --surface-sunken: #2c3136;
  --text: #e4e7ea;
  --muted: #9aa3ab;
  --faint: #6b747c;
  --border: #33383d;
  --border-strong: #444b52;

  --accent: #29c4d6;
  --accent-hover: #4fd6e6;
  --accent-soft: #123a40;
  --accent-fg: #04181a;
  --green: #3ddc7a;
  --green-soft: #123a24;
  --red: #ff5555;
  --red-soft: #3a1414;
  --red-text: #ff9a9a;

  --shadow-sm: 0 0 0 1px rgba(41, 196, 214, 0.08), 0 1px 2px rgba(0, 0, 0, 0.5);
  --shadow-md: 0 0 16px rgba(41, 196, 214, 0.12), 0 4px 16px rgba(0, 0, 0, 0.5);
  --shadow-lg: 0 0 32px rgba(41, 196, 214, 0.18), 0 16px 48px rgba(0, 0, 0, 0.6);

  --r-xl: 8px;
  --r-lg: 6px;
  --r-md: 4px;
  --r-sm: 3px;

  --pill-parent-bg: #123a40;
  --pill-parent-fg: #29c4d6;
  --pill-child-bg: #123a24;
  --pill-child-fg: #3ddc7a;
  --pill-notcompleted-bg: #3a1414;
  --pill-notcompleted-fg: #ff9a9a;
  --pill-mandatory-bg: #3a2a12;
  --pill-mandatory-fg: #ffa94d;
  --pill-optional-bg: #2a2f36;
  --pill-optional-fg: #9aa3ab;

  color-scheme: dark;
  font-family: ui-monospace, "SFMono-Regular", Consolas, "Liberation Mono", Menlo, monospace;

  /* A gear and a bolt, cyan on graphite. */
  --bg-pattern: url("data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20width='120'%20height='120'%20viewBox='0%200%20120%20120'%3E%3Cg%20fill='%2329c4d6'%20opacity='0.28'%3E%3Ccircle%20cx='30'%20cy='30'%20r='14'/%3E%3Ccircle%20cx='30'%20cy='30'%20r='6'%20fill='%231c1f22'/%3E%3Crect%20x='27'%20y='6'%20width='6'%20height='8'/%3E%3Crect%20x='27'%20y='46'%20width='6'%20height='8'/%3E%3Crect%20x='6'%20y='27'%20width='8'%20height='6'/%3E%3Crect%20x='46'%20y='27'%20width='8'%20height='6'/%3E%3Crect%20x='13'%20y='13'%20width='7'%20height='7'%20transform='rotate(45%2016.5%2016.5)'/%3E%3Crect%20x='40'%20y='13'%20width='7'%20height='7'%20transform='rotate(45%2043.5%2016.5)'/%3E%3Crect%20x='13'%20y='40'%20width='7'%20height='7'%20transform='rotate(45%2016.5%2043.5)'/%3E%3Crect%20x='40'%20y='40'%20width='7'%20height='7'%20transform='rotate(45%2043.5%2043.5)'/%3E%3Crect%20x='90'%20y='85'%20width='5'%20height='20'/%3E%3Crect%20x='80'%20y='95'%20width='20'%20height='5'/%3E%3C/g%3E%3C/svg%3E");
}

/* Warm neutrals and muted forest/sky tones rather than the app's cooler
   default — deliberately the calmest of the nature-themed additions, with
   no background pattern, so it reads as suited to an adult profile first
   and a family one second, per its brief. */
:root[data-theme="cabin"] {
  --bg: #f1efe9;
  --surface: #ffffff;
  --card: #ffffff;
  --surface-sunken: #e6e2d8;
  --text: #2e2a24;
  --muted: #6e6a60;
  --faint: #9c988c;
  --border: #ded8c8;
  --border-strong: #c7c0aa;

  --accent: #4a86b0;
  --accent-hover: #3c6f92;
  --accent-soft: #dcebf5;
  --accent-fg: #ffffff;
  --green: #3f7a55;
  --green-soft: #dcebe0;
  --red: #a1483a;
  --red-soft: #f0d8d2;
  --red-text: #6b2e24;

  --shadow-sm: 0 1px 2px rgba(46, 42, 36, 0.08), 0 1px 3px rgba(46, 42, 36, 0.06);
  --shadow-md: 0 4px 16px rgba(46, 42, 36, 0.14);
  --shadow-lg: 0 16px 48px rgba(46, 42, 36, 0.22);

  --r-xl: 16px;
  --r-lg: 12px;
  --r-md: 10px;
  --r-sm: 8px;

  --pill-parent-bg: #dcebf5;
  --pill-parent-fg: #1f4a63;
  --pill-child-bg: #dcebe0;
  --pill-child-fg: #1f4a30;
  --pill-notcompleted-bg: #f0d8d2;
  --pill-notcompleted-fg: #6b2e24;
  --pill-mandatory-bg: #ecdfc4;
  --pill-mandatory-fg: #6b5518;
  --pill-optional-bg: #e2ddd2;
  --pill-optional-fg: #5c5648;

  color-scheme: light;
}

/* Light lilac with a purple accent and mint for "done" — chosen so the
   panel of chips and cards stays legible even though the theme's whole
   point is to feel a bit silly. Nothing here draws on any actual
   character; the "monster" is a plain blob with two dot eyes. */
:root[data-theme="monster-lab"] {
  --bg: #f4f0fb;
  --surface: #ffffff;
  --card: #ffffff;
  --surface-sunken: #e9e1f7;
  --text: #2c2a3d;
  --muted: #746e94;
  --faint: #a79fc4;
  --border: #ded4f2;
  --border-strong: #c7b8ea;

  --accent: #8a4fd6;
  --accent-hover: #7539c2;
  --accent-soft: #ece0fb;
  --accent-fg: #ffffff;
  --green: #2fbf8f;
  --green-soft: #d3f5e9;
  --red: #e2584a;
  --red-soft: #fbe0dc;
  --red-text: #8a2e22;

  --shadow-sm: 0 1px 2px rgba(44, 42, 61, 0.12), 0 1px 3px rgba(44, 42, 61, 0.1);
  --shadow-md: 0 4px 16px rgba(44, 42, 61, 0.18);
  --shadow-lg: 0 16px 48px rgba(44, 42, 61, 0.28);

  --r-xl: 30px;
  --r-lg: 24px;
  --r-md: 18px;
  --r-sm: 14px;

  --pill-parent-bg: #e0d4fb;
  --pill-parent-fg: #4a2f8a;
  --pill-child-bg: #d3f5e9;
  --pill-child-fg: #146b4a;
  --pill-notcompleted-bg: #fbe0dc;
  --pill-notcompleted-fg: #8a2e22;
  --pill-mandatory-bg: #fde3d0;
  --pill-mandatory-fg: #8a5518;
  --pill-optional-bg: #e9e1f7;
  --pill-optional-fg: #4a4470;

  color-scheme: light;

  /* A blobby, two-eyed original creature and a drop of slime. */
  --bg-pattern: url("data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20width='130'%20height='130'%20viewBox='0%200%20130%20130'%3E%3Cg%20fill='%238a4fd6'%20opacity='0.3'%3E%3Cellipse%20cx='30'%20cy='34'%20rx='20'%20ry='16'/%3E%3Ccircle%20cx='60'%20cy='24'%20r='4'/%3E%3Ccircle%20cx='60'%20cy='34'%20r='3'/%3E%3Ccircle%20cx='60'%20cy='44'%20r='4'/%3E%3Ccircle%20cx='22'%20cy='28'%20r='4'%20fill='%23ffffff'/%3E%3Ccircle%20cx='38'%20cy='28'%20r='4'%20fill='%23ffffff'/%3E%3Ccircle%20cx='22'%20cy='28'%20r='2'%20fill='%232c2a3d'/%3E%3Ccircle%20cx='38'%20cy='28'%20r='2'%20fill='%232c2a3d'/%3E%3Cpath%20d='M100%2090%20q10%2010%200%2020%20q-10%20-6%200%20-20%20Z'/%3E%3C/g%3E%3C/svg%3E");
}

/* Olive and sand with a volcanic-gray accent for "must-do" and amber for
   the child pill — like an egg half-buried in sand. Chunky rather than
   sharp corners, for a kid-friendly but still legible card. */
:root[data-theme="dino-park"] {
  --bg: #efe9d6;
  --surface: #fbf7ea;
  --card: #fbf7ea;
  --surface-sunken: #e3dbbd;
  --text: #3a3424;
  --muted: #756b4a;
  --faint: #a89d75;
  --border: #d8cc9e;
  --border-strong: #c0b077;

  --accent: #6b7a2e;
  --accent-hover: #576223;
  --accent-soft: #e2e8c4;
  --accent-fg: #ffffff;
  --green: #4f8a3a;
  --green-soft: #dcecc4;
  --red: #a13a26;
  --red-soft: #ecd2c4;
  --red-text: #6b2417;

  --shadow-sm: 0 1px 2px rgba(58, 52, 36, 0.12), 0 1px 3px rgba(58, 52, 36, 0.1);
  --shadow-md: 0 4px 16px rgba(58, 52, 36, 0.18);
  --shadow-lg: 0 16px 48px rgba(58, 52, 36, 0.28);

  --r-xl: 14px;
  --r-lg: 11px;
  --r-md: 9px;
  --r-sm: 7px;

  --pill-parent-bg: #e2e8c4;
  --pill-parent-fg: #3f4a12;
  --pill-child-bg: #f5e2a0;
  --pill-child-fg: #7a5c0a;
  --pill-notcompleted-bg: #ecd2c4;
  --pill-notcompleted-fg: #6b2417;
  --pill-mandatory-bg: #dcdcd0;
  --pill-mandatory-fg: #4a473c;
  --pill-optional-bg: #dfe6e6;
  --pill-optional-fg: #33504f;

  color-scheme: light;

  /* A three-toed footprint and a fallen leaf. */
  --bg-pattern: url("data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20width='130'%20height='130'%20viewBox='0%200%20130%20130'%3E%3Cg%20fill='%236b7a2e'%20opacity='0.3'%3E%3Cellipse%20cx='30'%20cy='40'%20rx='10'%20ry='13'/%3E%3Cellipse%20cx='16'%20cy='22'%20rx='5'%20ry='9'%20transform='rotate(-20%2016%2022)'/%3E%3Cellipse%20cx='30'%20cy='16'%20rx='5'%20ry='9'/%3E%3Cellipse%20cx='44'%20cy='22'%20rx='5'%20ry='9'%20transform='rotate(20%2044%2022)'/%3E%3Cellipse%20cx='100'%20cy='90'%20rx='9'%20ry='4'%20transform='rotate(30%20100%2090)'/%3E%3C/g%3E%3C/svg%3E");
}

/* A dark, original "mission control" look — navy surfaces, a red primary
   accent, and silver-blue readouts, with crisp near-square corners for a
   HUD feel. Deliberately generic (a radar sweep and readout bars, no
   badge, no emblem) so it doesn't lean on any actual agency or franchise. */
:root[data-theme="mission-base"] {
  --bg: #0e1420;
  --surface: #141b2b;
  --card: #141b2b;
  --surface-sunken: #1a2233;
  --text: #dfe4ee;
  --muted: #8f9ab0;
  --faint: #5f6a80;
  --border: #232c3f;
  --border-strong: #303a50;

  --accent: #d64545;
  --accent-hover: #ef5a5a;
  --accent-soft: #3a1418;
  --accent-fg: #ffffff;
  --green: #3ddc7a;
  --green-soft: #123a24;
  --red: #d64545;
  --red-soft: #3a1418;
  --red-text: #ff9a9a;

  --shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.5);
  --shadow-md: 0 4px 16px rgba(0, 0, 0, 0.55);
  --shadow-lg: 0 16px 48px rgba(0, 0, 0, 0.65);

  --r-xl: 6px;
  --r-lg: 4px;
  --r-md: 3px;
  --r-sm: 2px;

  --pill-parent-bg: #1a2a40;
  --pill-parent-fg: #8fb4e0;
  --pill-child-bg: #123a24;
  --pill-child-fg: #3ddc7a;
  --pill-notcompleted-bg: #3a1418;
  --pill-notcompleted-fg: #ff9a9a;
  --pill-mandatory-bg: #3a2a12;
  --pill-mandatory-fg: #ffbb55;
  --pill-optional-bg: #242c3d;
  --pill-optional-fg: #9aa6ba;

  color-scheme: dark;
  font-family: ui-monospace, "SFMono-Regular", Consolas, "Liberation Mono", Menlo, monospace;

  /* A radar sweep and a few readout bars — control-room dressing, not an
     insignia. */
  --bg-pattern: url("data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20width='140'%20height='140'%20viewBox='0%200%20140%20140'%3E%3Cg%20stroke='%238fb4e0'%20stroke-width='2'%20fill='none'%20opacity='0.28'%3E%3Ccircle%20cx='35'%20cy='35'%20r='10'/%3E%3Ccircle%20cx='35'%20cy='35'%20r='18'/%3E%3Ccircle%20cx='35'%20cy='35'%20r='26'/%3E%3Cline%20x1='35'%20y1='2'%20x2='35'%20y2='12'/%3E%3Cline%20x1='35'%20y1='58'%20x2='35'%20y2='68'/%3E%3Cline%20x1='2'%20y1='35'%20x2='12'%20y2='35'/%3E%3Cline%20x1='58'%20y1='35'%20x2='68'%20y2='35'/%3E%3C/g%3E%3Cg%20fill='%238fb4e0'%20opacity='0.28'%3E%3Ccircle%20cx='35'%20cy='35'%20r='2.5'/%3E%3Crect%20x='95'%20y='90'%20width='30'%20height='4'/%3E%3Crect%20x='95'%20y='98'%20width='20'%20height='4'/%3E%3Crect%20x='95'%20y='106'%20width='24'%20height='4'/%3E%3C/g%3E%3C/svg%3E");
}

/* Neutral surfaces so a mix of primary colors (the pill/chip set below)
   reads clearly against them — built for the extra-legible, kid-friendly
   layout its brief asks for, not for a particular building-block brand:
   the background tile below is four plain flat squares, no studs. */
:root[data-theme="block-world"] {
  --bg: #f5f5f2;
  --surface: #ffffff;
  --card: #ffffff;
  --surface-sunken: #e8e8e2;
  --text: #1f2430;
  --muted: #63697a;
  --faint: #9aa0ac;
  --border: #dcdcd4;
  --border-strong: #c4c4b8;

  --accent: #2e6fe0;
  --accent-hover: #2559ba;
  --accent-soft: #dbe7fb;
  --accent-fg: #ffffff;
  --green: #2fae4a;
  --green-soft: #dcf5e0;
  --red: #e04b3a;
  --red-soft: #fbdcd6;
  --red-text: #8a2418;

  --shadow-sm: 0 1px 2px rgba(31, 36, 48, 0.08), 0 1px 3px rgba(31, 36, 48, 0.06);
  --shadow-md: 0 4px 16px rgba(31, 36, 48, 0.14);
  --shadow-lg: 0 16px 48px rgba(31, 36, 48, 0.22);

  --r-xl: 18px;
  --r-lg: 14px;
  --r-md: 11px;
  --r-sm: 9px;

  --pill-parent-bg: #dbe7fb;
  --pill-parent-fg: #1a3f8a;
  --pill-child-bg: #dcf5e0;
  --pill-child-fg: #146b2a;
  --pill-notcompleted-bg: #fbdcd6;
  --pill-notcompleted-fg: #8a2418;
  --pill-mandatory-bg: #fdf0c0;
  --pill-mandatory-fg: #7a5e0a;
  --pill-optional-bg: #e8e0f5;
  --pill-optional-fg: #4a2f8a;

  color-scheme: light;

  /* Four flat, rounded squares — a generic building-block motif. */
  --bg-pattern: url("data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20width='120'%20height='120'%20viewBox='0%200%20120%20120'%3E%3Cg%20opacity='0.28'%3E%3Crect%20x='10'%20y='10'%20width='30'%20height='30'%20rx='6'%20fill='%232e6fe0'/%3E%3Crect%20x='46'%20y='10'%20width='30'%20height='30'%20rx='6'%20fill='%232fae4a'/%3E%3Crect%20x='10'%20y='46'%20width='30'%20height='30'%20rx='6'%20fill='%23e04b3a'/%3E%3Crect%20x='46'%20y='46'%20width='30'%20height='30'%20rx='6'%20fill='%23f2c230'/%3E%3C/g%3E%3C/svg%3E");
}

/* The calmest and most "grown-up" of this batch: sage, dusty blue and
   terracotta on warm beige, no background pattern and a restrained radius
   — quiet order rather than decoration, on purpose. */
:root[data-theme="cozy-home"] {
  --bg: #f3ede4;
  --surface: #fffbf5;
  --card: #fffbf5;
  --surface-sunken: #e8ddc9;
  --text: #332f28;
  --muted: #7a7161;
  --faint: #a89d89;
  --border: #ddd0b8;
  --border-strong: #c7b898;

  --accent: #7c8f6e;
  --accent-hover: #66795a;
  --accent-soft: #e2e8da;
  --accent-fg: #ffffff;
  --green: #6b8f5a;
  --green-soft: #dfe8d4;
  --red: #b5583c;
  --red-soft: #f0dcd2;
  --red-text: #7a3620;

  --shadow-sm: 0 1px 2px rgba(51, 47, 40, 0.08), 0 1px 3px rgba(51, 47, 40, 0.06);
  --shadow-md: 0 4px 16px rgba(51, 47, 40, 0.14);
  --shadow-lg: 0 16px 48px rgba(51, 47, 40, 0.22);

  --r-xl: 20px;
  --r-lg: 15px;
  --r-md: 12px;
  --r-sm: 10px;

  --pill-parent-bg: #d8e0ea;
  --pill-parent-fg: #2f4a63;
  --pill-child-bg: #dfe8d4;
  --pill-child-fg: #3f5c2e;
  --pill-notcompleted-bg: #f0dcd2;
  --pill-notcompleted-fg: #7a3620;
  --pill-mandatory-bg: #f0e0c4;
  --pill-mandatory-fg: #7a5e18;
  --pill-optional-bg: #ecdcd0;
  --pill-optional-fg: #7a4a30;

  color-scheme: light;
}

* { box-sizing: border-box; }

html {
  -webkit-text-size-adjust: 100%;
}

/* While the task sheet is open the page behind it must not scroll —
   otherwise a flick aimed at the form drags the list underneath. */
body.sheet-open { overflow: hidden; }

body {
  margin: 0;
  background-color: var(--bg);
  background-image: var(--bg-pattern);
  background-repeat: repeat;
  color: var(--text);
  line-height: 1.45;
  /* App-like touch behaviour: no grey flash on tap, no double-tap zoom
     delay, and no scroll chaining/rubber-band past the ends of the page. */
  -webkit-tap-highlight-color: transparent;
  touch-action: manipulation;
  overscroll-behavior-y: none;
  -webkit-font-smoothing: antialiased;
}

/* ---- app shell ------------------------------------------------------- */

#app {
  min-height: 100dvh;
  padding-left: var(--safe-l);
  padding-right: var(--safe-r);
}

/* Top bar: family on the left, who you're acting as on the right. Sticky
   rather than fixed so it participates in the page's own scroll container,
   and translucent so content scrolling underneath reads as depth. */
.appbar {
  position: sticky;
  top: 0;
  z-index: 40;
  padding-top: var(--safe-t);
  background: color-mix(in srgb, var(--surface) 82%, transparent);
  backdrop-filter: saturate(180%) blur(18px);
  -webkit-backdrop-filter: saturate(180%) blur(18px);
  border-bottom: 1px solid var(--border);
}
.appbar-inner {
  max-width: var(--page);
  margin: 0 auto;
  min-height: 52px;
  padding: 8px var(--gutter);
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
}
.appbar-left,
.appbar-right {
  display: flex;
  align-items: center;
  min-width: 0;
}
.appbar-family {
  font-size: 1.05rem;
  font-weight: 650;
  letter-spacing: -0.01em;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* A native <select> laid transparently over a styled chip: the chip does
   the looking, the select does the picking (so switching family or user
   still opens the platform's own wheel/menu on a phone). */
.chip {
  position: relative;
  display: inline-flex;
  align-items: center;
  gap: 6px;
  max-width: 100%;
  min-height: 36px;
  padding: 4px 10px 4px 4px;
  border-radius: 999px;
  border: 1px solid var(--border);
  background: var(--surface);
}
.chip.chip-plain {
  border-color: transparent;
  background: transparent;
  padding-left: 0;
}
.chip-select {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  opacity: 0;
  border: none;
  padding: 0;
  margin: 0;
  cursor: pointer;
  -webkit-appearance: none;
  appearance: none;
}
.chip-name {
  font-size: 0.9rem;
  font-weight: 550;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.chip-caret {
  font-size: 18px;
  max-width: 18px;
  overflow: hidden;
  color: var(--faint);
  flex: none;
}
.avatar {
  width: 28px;
  height: 28px;
  overflow: hidden;
  border-radius: 50%;
  flex: none;
  display: grid;
  place-items: center;
  font-size: 0.8rem;
  font-weight: 650;
  color: #fff;
  background: var(--accent);
  text-transform: uppercase;
}
.avatar.child { background: var(--green); }
.avatar.lg { width: 40px; height: 40px; font-size: 1rem; }

/* Bottom tab bar — the app's primary navigation on a phone. Fixed to the
   bottom edge and padded past the home indicator; on a wide viewport it
   drops out of that mode and sits under the app bar as an ordinary row
   (see the desktop block at the end of this file). */
.tabbar {
  position: fixed;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 50;
  background: color-mix(in srgb, var(--surface) 86%, transparent);
  backdrop-filter: saturate(180%) blur(18px);
  -webkit-backdrop-filter: saturate(180%) blur(18px);
  border-top: 1px solid var(--border);
  padding-bottom: var(--safe-b);
  padding-left: var(--safe-l);
  padding-right: var(--safe-r);
}
.tabbar-inner {
  max-width: var(--page);
  margin: 0 auto;
  display: flex;
}
.tabbar button {
  flex: 1 1 0;
  min-width: 0;
  overflow: hidden;
  height: var(--tabbar-h);
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 2px;
  padding: 0 2px;
  border: none;
  border-radius: 0;
  background: transparent;
  color: var(--muted);
  font-size: 0.68rem;
  font-weight: 550;
  letter-spacing: 0.01em;
}
.tabbar button .material-symbols-outlined {
  font-size: 23px;
  font-variation-settings: "FILL" 0, "wght" 400;
  transition: font-variation-settings 0.15s ease;
}
.tabbar button.active {
  color: var(--accent);
}
.tabbar button.active .material-symbols-outlined {
  font-variation-settings: "FILL" 1, "wght" 500;
}
.tabbar button .tab-label {
  max-width: 100%;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.tabbar button:active { transform: none; }
@media (hover: hover) {
  .tabbar button:hover {
    background: color-mix(in srgb, var(--text) 5%, transparent);
    border-color: transparent;
    color: var(--text);
  }
  .tabbar button.active:hover { color: var(--accent); }
}

.content {
  display: block;
  max-width: var(--page);
  margin: 0 auto;
  padding: 16px var(--gutter) calc(var(--tabbar-h) + var(--safe-b) + 28px);
}
/* Screens with no tab bar (login-adjacent: onboarding, the "who's using
   this?" picker, the kiosk key prompt) don't need to reserve room for it. */
.content.no-tabbar {
  padding-bottom: calc(var(--safe-b) + 32px);
}

/* ---- type ------------------------------------------------------------ */

h1, h2, h3 { margin: 0 0 8px; letter-spacing: -0.01em; }
h1 { font-size: 1.5rem; font-weight: 700; }
h2 { font-size: 1.05rem; font-weight: 650; }
h3 { font-size: 0.95rem; font-weight: 650; }
p { color: var(--muted); margin: 0 0 12px; }

/* The large screen title at the top of each tab's content — the phone-app
   convention of naming where you are, since the tab bar's own labels are
   too small to serve as the heading. */
.screen-title {
  font-size: 1.75rem;
  font-weight: 700;
  letter-spacing: -0.02em;
  margin: 4px 0 16px;
}
.section-label {
  font-size: 0.75rem;
  font-weight: 650;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--faint);
  margin: 22px 4px 8px;
}
.hint { color: var(--muted); font-size: 0.85rem; }
.hint a { color: var(--accent); font-weight: 600; }
.empty { color: var(--faint); padding: 14px 0; font-size: 0.9rem; }

/* ---- cards & rows ---------------------------------------------------- */

.card {
  background: var(--card);
  border: 1px solid var(--border);
  border-radius: var(--r-lg);
  padding: 16px;
  margin-bottom: 14px;
  box-shadow: var(--shadow-sm);
}
.card > h2:first-child,
.card > h3:first-child { margin-top: 0; }


.row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: 8px 12px;
  padding: 12px 0;
  border-bottom: 1px solid var(--border);
}
.row:last-child { border-bottom: none; }
.row.expandable {
  cursor: pointer;
  margin: 0 -16px;
  padding-left: 16px;
  padding-right: 16px;
}
.row.expandable:active { background: var(--surface-sunken); }
@media (hover: hover) {
  .row.expandable:hover { background: color-mix(in srgb, var(--text) 4%, transparent); }
}
.row .chevron { color: var(--faint); flex: none; }

/* The panel a .row.expandable reveals when toggled open — indented and
   set off from the row above it so it reads as "belonging to" that row
   rather than as the next item in the list. */
.row-detail {
  padding: 4px 0 16px 12px;
  border-bottom: 1px solid var(--border);
  border-left: 2px solid var(--border-strong);
  margin-left: 4px;
}
.row-detail:last-child { border-bottom: none; }
.row-detail .field:first-child { margin-top: 10px; }

/* The first child is usually a text block and the rest are buttons/controls.
   Letting the text grow and giving it a wrap point (rather than a fixed
   width) means a row degrades gracefully as its container narrows: buttons
   stay alongside the text as long as there's room, then drop to their own
   line below it — without a breakpoint tied to any specific device width. */
.row > *:first-child {
  flex: 1 1 180px;
  min-width: 0;
}

.grid-2 {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 10px;
}
.grid-3 {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 10px;
}
/* Narrower than about an iPhone SE, three money figures side by side stop
   fitting whatever size they're set at, so they become three labelled rows
   instead — which always fits, however large the amounts get. */
@media (max-width: 359px) {
  .grid-3 {
    grid-template-columns: 1fr;
    gap: 0;
  }
  .grid-3 .stat {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 10px;
    text-align: left;
    padding: 5px 2px;
  }
  .grid-3 .stat .value { font-size: 1.15rem; order: 2; }
  .grid-3 .stat .label { text-align: left; }
}

/* ---- controls -------------------------------------------------------- */

/* 16px is deliberate on the text inputs: iOS Safari zooms the viewport in
   whenever a focused field's text is smaller than that, which on a phone
   reads as the page lurching sideways mid-typing. */
button, select, input, textarea {
  font-family: inherit;
  font-size: 1rem;
  border-radius: var(--r-md);
  border: 1px solid var(--border-strong);
  padding: 10px 12px;
  background: var(--surface);
  color: var(--text);
  max-width: 100%;
}
input, select, textarea { width: 100%; }
input[type="checkbox"], input[type="radio"] { width: auto; }
select {
  -webkit-appearance: none;
  appearance: none;
  padding-right: 34px;
  background-image: linear-gradient(45deg, transparent 50%, var(--muted) 50%), linear-gradient(135deg, var(--muted) 50%, transparent 50%);
  background-position: calc(100% - 18px) 50%, calc(100% - 13px) 50%;
  background-size: 5px 5px, 5px 5px;
  background-repeat: no-repeat;
}
input:focus-visible, select:focus-visible, textarea:focus-visible, button:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}
input::placeholder { color: var(--faint); }

button {
  width: auto;
  cursor: pointer;
  min-height: 44px; /* comfortable thumb target */
  padding: 10px 18px;
  font-weight: 600;
  background: var(--accent);
  color: var(--accent-fg);
  border-color: var(--accent);
  transition: transform 0.08s ease, background-color 0.12s ease, opacity 0.12s ease;
}
button:active { transform: scale(0.97); }
@media (hover: hover) {
  button:hover { background: var(--accent-hover); border-color: var(--accent-hover); }
}
button.secondary {
  background: var(--surface);
  color: var(--text);
  border-color: var(--border-strong);
}
@media (hover: hover) {
  button.secondary:hover { background: var(--surface-sunken); border-color: var(--border-strong); }
}
button.ghost {
  background: transparent;
  color: var(--accent);
  border-color: transparent;
  padding-left: 8px;
  padding-right: 8px;
}
button.danger {
  background: var(--red);
  border-color: var(--red);
  color: #fff;
}
@media (hover: hover) {
  button.danger:hover { background: var(--red); border-color: var(--red); filter: brightness(0.93); }
}
button:disabled { opacity: 0.45; cursor: default; }
button:disabled:active { transform: none; }
button.block { width: 100%; }

label {
  display: block;
  font-size: 0.82rem;
  font-weight: 550;
  color: var(--muted);
  margin-bottom: 6px;
}
.field { margin-bottom: 14px; }
.field:last-child { margin-bottom: 0; }
.input-full { width: 100%; }

/* An input with a button glued to its right — rename family, rename
   yourself, type-to-confirm. Wraps to two lines when there isn't room. */
.input-row {
  display: flex;
  gap: 8px;
  flex-wrap: wrap;
  align-items: center;
}
.input-row input, .input-row textarea { flex: 1 1 160px; width: auto; }

/* Styled like a terminal on purpose — the one field in the app that's
   deliberately theme-independent rather than drawn from the design tokens,
   since it's illustrating a shell command rather than app content. The
   same fixed black-and-green look in both light and dark mode is what
   reads as "terminal" instead of "input field that happens to be dark
   here". Used for the personal access token page's grpcurl example,
   itself a <textarea readonly> rather than an <input> so a multi-line
   command can wrap onto its own lines instead of scrolling sideways. */
.terminal-cmd {
  resize: none;
  line-height: 1.5;
  background: #0a0e0a;
  color: #3ddc4a;
  border-color: #0a0e0a;
  font-family: ui-monospace, "SFMono-Regular", Consolas, "Liberation Mono", Menlo, monospace;
  /* The 16px floor above exists to stop iOS Safari zooming the viewport on
     focus, which only happens for a field the on-screen keyboard opens for
     — this one is readonly (tap selects instead, see wireCopyButton), so no
     keyboard ever appears and it's free to go smaller. Doing so is the
     difference between the Authorization header line wrapping or not on a
     360px-ish phone. */
  font-size: 0.8rem;
}

/* Fixed white-on-black regardless of theme, same reasoning as .terminal-cmd
   above: a scanner-friendly code needs dark modules on a light background,
   and that can't follow the rest of the page into dark mode. */
.qr-panel {
  display: flex;
  justify-content: center;
  margin-top: 10px;
  padding: 14px;
  background: #fff;
  border-radius: var(--r-lg);
  box-shadow: var(--shadow-sm);
}
.qr-panel svg {
  width: 100%;
  max-width: 220px;
  height: auto;
}

.actions { display: flex; gap: 8px; flex-wrap: wrap; }
/* On a phone a lone primary action reads better spanning the card. */
@media (max-width: 520px) {
  .actions.stack { flex-direction: column; align-items: stretch; }
  .actions.stack button { width: 100%; }
}

/* iOS-style segmented control, used for the mutually-exclusive choices in
   the task form (repeat mode, mandatory/optional). */
.segmented {
  display: flex;
  gap: 2px;
  padding: 3px;
  border-radius: var(--r-md);
  background: var(--surface-sunken);
  border: 1px solid var(--border);
}
.segmented button {
  flex: 1 1 0;
  min-width: 0;
  min-height: 36px;
  padding: 7px 8px;
  font-size: 0.88rem;
  font-weight: 550;
  border: none;
  border-radius: 9px;
  background: transparent;
  color: var(--muted);
  box-shadow: none;
}
@media (hover: hover) {
  .segmented button:hover { background: transparent; color: var(--text); }
}
.segmented button.active {
  background: var(--surface);
  color: var(--text);
  box-shadow: var(--shadow-sm);
}
@media (hover: hover) {
  .segmented button.active:hover { background: var(--surface); }
}

/* Tap-to-toggle chips, replacing checkbox lists for the days a task repeats
   on and the children it's assigned to. The checkbox is still there (hidden)
   so the form reads its state exactly as before — :has() does the styling. */
.chip-group {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}
.toggle-chip {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 38px;
  padding: 6px 14px;
  margin: 0;
  border-radius: 999px;
  border: 1px solid var(--border-strong);
  background: var(--surface);
  color: var(--muted);
  font-size: 0.88rem;
  font-weight: 550;
  cursor: pointer;
  user-select: none;
  -webkit-user-select: none;
  transition: transform 0.08s ease;
}
.toggle-chip:active { transform: scale(0.96); }
.toggle-chip input {
  position: absolute;
  opacity: 0;
  pointer-events: none;
  width: 0;
  height: 0;
}
.toggle-chip:has(input:checked) {
  background: var(--accent);
  border-color: var(--accent);
  color: var(--accent-fg);
}
.toggle-chip:has(input:focus-visible) {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

/* A checkbox that reads as a settings switch row rather than a bare box. */
.switch-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  margin: 0;
  font-size: 0.95rem;
  font-weight: 500;
  color: var(--text);
  cursor: pointer;
  min-height: 32px;
}
.switch-row input { flex: none; width: 20px; height: 20px; accent-color: var(--accent); }

/* Deliberately narrow on desktop, where there's plenty of spare width to
   leave unused; on a narrow viewport that same fixed width just wastes the
   little room there is; full width there is both easier to tap and easier
   to read what's typed. */
.input-price { width: 8em; }
.input-date { width: 11em; }
.input-interval { width: 6em; }
.input-cron { width: 14em; }
@media (max-width: 520px) {
  .input-price,
  .input-date,
  .input-interval,
  .input-cron {
    width: 100%;
  }
}

/* ---- pills ----------------------------------------------------------- */

.pill {
  display: inline-block;
  padding: 2px 8px;
  border-radius: 999px;
  font-size: 0.7rem;
  font-weight: 600;
  letter-spacing: 0.01em;
  vertical-align: 1px;
  background: var(--surface-sunken);
  color: var(--muted);
}
.pill.parent { background: var(--pill-parent-bg); color: var(--pill-parent-fg); }
.pill.child { background: var(--pill-child-bg); color: var(--pill-child-fg); }
.pill.notcompleted { background: var(--pill-notcompleted-bg); color: var(--pill-notcompleted-fg); }
.pill.mandatory { background: var(--pill-mandatory-bg); color: var(--pill-mandatory-fg); }
.pill.optional { background: var(--pill-optional-bg); color: var(--pill-optional-fg); }

/* ---- task rows & stats ----------------------------------------------- */

.task-title { font-weight: 600; display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.task-meta { font-size: 0.82rem; color: var(--muted); margin-top: 2px; }

/* The icon that leads a task's title, given a tinted round tile so a list
   of chores scans as a list of things rather than a wall of text. */
.task-icon {
  width: 34px;
  height: 34px;
  overflow: hidden;
  border-radius: 11px;
  flex: none;
  display: inline-grid;
  place-items: center;
  background: var(--accent-soft);
  color: var(--accent);
}
.task-icon .material-symbols-outlined { font-size: 20px; }
.task-row-main { display: flex; align-items: center; gap: 12px; min-width: 0; }
.task-row-text { min-width: 0; }

/* The "Must do" / "Can do" heading above each group of today's tasks. Tighter
   than a standalone .section-label because it sits between rows inside a card,
   not between cards — and the first one shouldn't push the list away from the
   child's name above it. */
.occurrence-group {
  margin: 14px 0 2px;
}
.occurrence-group:first-child {
  margin-top: 6px;
}

/* History rows for occurrences that were due but never completed — dimmed
   so a glance at the list still reads as "mostly done things", with the
   pill above doing the explicit labeling. */
.history-row-incomplete { opacity: 0.62; }

.stat { text-align: center; }
.stat .value {
  font-size: 1.4rem;
  font-weight: 700;
  letter-spacing: -0.02em;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}
.grid-3 .stat .value { font-size: clamp(0.95rem, 4.4vw, 1.35rem); }
.stat .label {
  font-size: 0.72rem;
  font-weight: 550;
  color: var(--muted);
  text-transform: uppercase;
  letter-spacing: 0.04em;
}
/* The stats strip inside a child's card reads as one inset panel rather
   than three floating numbers. */
.stat-strip {
  background: var(--surface-sunken);
  border-radius: var(--r-md);
  padding: 12px 10px;
  margin-top: 12px;
}

/* The big round tick that completes a task — sized as a proper thumb
   target, not a 32px dot. */
.checkbtn {
  width: 44px;
  height: 44px;
  overflow: hidden;
  min-height: 44px;
  border-radius: 50%;
  padding: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  flex: none;
  border: 2px solid var(--border-strong);
}
.checkbtn .material-symbols-outlined { font-size: 24px; }
.checkbtn.done {
  background: var(--green);
  border-color: var(--green);
  color: #fff;
}
@media (hover: hover) {
  .checkbtn.done:hover { background: var(--green); border-color: var(--green); }
}
.checkbtn.todo {
  background: transparent;
  color: transparent;
}
@media (hover: hover) {
  .checkbtn.todo:hover { background: var(--surface-sunken); border-color: var(--accent); }
}
.checkbtn:active { transform: scale(0.9); }

/* A fixed-width icon button — used for pause/resume so toggling between
   the two doesn't change the button's width and shove its neighbors
   sideways, the way swapping "Pause" for "Gjenoppta"/"Resume" text did. */
.btn-icon {
  width: 44px;
  padding: 0;
  overflow: hidden;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: none;
}
.btn-icon .material-symbols-outlined { font-size: 20px; }

/* ---- floating action button ------------------------------------------ */

/* "Add a task" is the one action on the Tasks screen that's worth a
   permanent, thumb-reachable home, so it rides above the tab bar instead
   of sitting at the bottom of a long list. */
.fab {
  position: fixed;
  right: max(var(--gutter), var(--safe-r));
  bottom: calc(var(--tabbar-h) + var(--safe-b) + 16px);
  z-index: 45;
  display: inline-flex;
  align-items: center;
  gap: 8px;
  height: 52px;
  padding: 0 20px 0 16px;
  border-radius: 999px;
  box-shadow: var(--shadow-md);
  font-weight: 600;
}
.fab .material-symbols-outlined { font-size: 22px; }

/* ---- bottom sheet / modal -------------------------------------------- */

/* The task editor opens over the list instead of appearing beneath it: on a
   phone it's a bottom sheet that slides up, on a wide screen a centred
   dialog. Either way you edit one task without losing your place in the
   list behind it. */
.sheet-backdrop {
  position: fixed;
  inset: 0;
  z-index: 80;
  background: rgba(9, 12, 20, 0.45);
  backdrop-filter: blur(2px);
  -webkit-backdrop-filter: blur(2px);
  display: flex;
  align-items: flex-end;
  justify-content: center;
  animation: fade-in 0.18s ease;
}
.sheet {
  width: 100%;
  max-width: var(--page);
  max-height: 92dvh;
  display: flex;
  flex-direction: column;
  background: var(--bg);
  border-radius: var(--r-xl) var(--r-xl) 0 0;
  box-shadow: var(--shadow-lg);
  animation: sheet-up 0.24s cubic-bezier(0.32, 0.72, 0, 1);
}
.sheet-header {
  position: relative;
  flex: none;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 14px 16px 12px;
  border-bottom: 1px solid var(--border);
}
/* The drag-handle affordance every phone sheet has. Decorative — dragging
   isn't wired up; tapping outside or the close button is how it dismisses. */
.sheet-header::before {
  content: "";
  position: absolute;
  top: 6px;
  left: 50%;
  transform: translateX(-50%);
  width: 36px;
  height: 4px;
  border-radius: 999px;
  background: var(--border-strong);
}
.sheet-title { font-size: 1.05rem; font-weight: 650; margin: 0; }
.sheet-body {
  overflow-y: auto;
  -webkit-overflow-scrolling: touch;
  overscroll-behavior: contain;
  padding: 16px var(--gutter) calc(var(--safe-b) + 20px);
}
.sheet-body .card { box-shadow: none; }
.sheet-close {
  width: 36px;
  height: 36px;
  overflow: hidden;
  min-height: 36px;
  padding: 0;
  border-radius: 50%;
  flex: none;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  background: var(--surface-sunken);
  border-color: transparent;
  color: var(--muted);
}
@media (hover: hover) {
  .sheet-close:hover { background: var(--border); border-color: transparent; }
}

@keyframes sheet-up {
  from { transform: translateY(6%); opacity: 0.6; }
  to { transform: translateY(0); opacity: 1; }
}
@keyframes fade-in {
  from { opacity: 0; }
  to { opacity: 1; }
}
@keyframes toast-in {
  from { transform: translateY(-120%); opacity: 0; }
  to { transform: translateY(0); opacity: 1; }
}

/* ---- error toast ------------------------------------------------------ */

/* Fixed rather than in normal document flow: inserted at the top of the
   page like this used to push everything below it down the moment an
   error appeared. On a real click (not just a re-render), that shift
   between mousedown/touchstart and mouseup/touchend could land the second
   half of the click on whatever control had shifted into its place — e.g.
   a validation error on the task form's Save button pushing "select all
   children" up underneath the cursor. Overlaying it instead means showing
   or clearing an error never moves anything else on the page. */
.error {
  position: fixed;
  top: calc(var(--safe-t) + 8px);
  left: max(8px, var(--safe-l));
  right: max(8px, var(--safe-r));
  z-index: 100;
  max-width: calc(var(--page) - 16px);
  margin: 0 auto;
  display: flex;
  align-items: center;
  gap: 10px;
  background: var(--red-soft);
  color: var(--red-text);
  border: 1px solid color-mix(in srgb, var(--red) 35%, transparent);
  padding: 12px 14px;
  border-radius: var(--r-md);
  font-size: 0.9rem;
  font-weight: 500;
  box-shadow: var(--shadow-md);
  animation: toast-in 0.22s cubic-bezier(0.32, 0.72, 0, 1);
}
.error .material-symbols-outlined { font-size: 20px; flex: none; }
.error span.error-text { flex: 1 1 auto; min-width: 0; }
.error button {
  flex: none;
  width: 30px;
  height: 30px;
  overflow: hidden;
  min-height: 30px;
  padding: 0;
  border-radius: 50%;
  background: transparent;
  border-color: transparent;
  color: inherit;
  display: inline-flex;
  align-items: center;
  justify-content: center;
}
@media (hover: hover) {
  .error button:hover { background: color-mix(in srgb, var(--red) 18%, transparent); border-color: transparent; }
}

/* A standing notice, not an error: shown while a parent is looking at the
   app through one of their children's accounts. */
.notice-bar {
  display: flex;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;
  background: var(--accent-soft);
  color: var(--text);
  border-radius: var(--r-md);
  padding: 10px 12px;
  margin-bottom: 14px;
  font-size: 0.88rem;
}
.notice-bar .notice-text { flex: 1 1 auto; min-width: 0; }
.notice-bar > .material-symbols-outlined { font-size: 20px; flex: none; color: var(--accent); }
.notice-bar button { min-height: 34px; padding: 6px 12px; font-size: 0.85rem; }

/* ---- icon picker ------------------------------------------------------ */

.icon-choices {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(48px, 1fr));
  gap: 6px;
  max-height: 220px;
  overflow-y: auto;
  -webkit-overflow-scrolling: touch;
  padding: 4px;
  border-radius: var(--r-md);
  background: var(--surface-sunken);
}
.icon-choices button {
  min-height: 46px;
  padding: 0;
  overflow: hidden;
  display: inline-flex;
  align-items: center;
  justify-content: center;
}
.icon-selected {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 8px;
  margin-bottom: 8px;
  border-radius: var(--r-md);
  background: var(--surface-sunken);
}
.icon-selected .material-symbols-outlined { font-size: 1.4rem; }
.icon-selected span:nth-child(2) { flex: 1 1 auto; font-size: 0.9rem; }
.icon-selected button { min-height: 36px; padding: 6px 12px; font-size: 0.85rem; }

/* ---- centred single-card screens (login, onboarding, kiosk key) -------- */

.hero {
  max-width: 380px;
  margin: 8vh auto 0;
  text-align: center;
}
.hero .logo {
  border-radius: 24%;
  box-shadow: var(--shadow-md);
  margin-bottom: 14px;
}
.hero h1 { font-size: 1.9rem; }
.logo { border-radius: 24%; }

/* ---- welcome page (logged out) ---------------------------------------- */

/* Wider than the app shell's reading column: this page carries a row of
   phone screenshots, which needs room on a desktop window. */
.welcome {
  max-width: 720px;
}

/* Sized so the button clears the fold on a phone without the page looking
   padded out on a laptop. A returning user should see the logo, the name and
   Log in without scrolling — the explanation below is for everyone else. */
.welcome-hero {
  text-align: center;
  padding: 4vh 0 6vh;
  max-width: 380px;
  margin: 0 auto;
}
.welcome-hero .logo {
  border-radius: 24%;
  box-shadow: var(--shadow-md);
  margin-bottom: 16px;
}
.welcome-hero h1 {
  font-size: 2rem;
  letter-spacing: -0.02em;
  margin-bottom: 6px;
}
.welcome-hero p {
  font-size: 1.05rem;
  margin-bottom: 22px;
}
/* A quiet second option below the primary Log in button — most visitors
   should never notice it, so it's plain text rather than a second button. */
.welcome-dashboard-link {
  display: inline-block;
  margin-top: 14px;
  color: var(--muted);
  text-decoration: underline;
}
.welcome-lang {
  margin-top: 18px;
}

.welcome-section {
  margin-bottom: 34px;
}
.welcome-section h2 {
  font-size: 1.25rem;
  margin-bottom: 16px;
}

.steps {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: 14px;
}
.step {
  display: flex;
  gap: 14px;
  align-items: flex-start;
  background: var(--card);
  border: 1px solid var(--border);
  border-radius: var(--r-lg);
  padding: 16px;
  box-shadow: var(--shadow-sm);
}
.step h3 {
  margin: 0 0 4px;
}
/* A bare icon rather than a tinted badge tile — tried both, this read
   cleaner against the card background. Keeps a fixed box (flex: none,
   width/height) purely so the three icons still line up on the same
   baseline despite each glyph's slightly different natural shape, and
   overflow: hidden for the same reason every icon container needs it. */
.step-icon {
  flex: none;
  width: 40px;
  height: 40px;
  overflow: hidden;
  display: grid;
  place-items: center;
  color: var(--accent);
  font-size: 28px;
}

/* One phone per row on a phone, three across once there's room. The images
   are the app's own screenshots, so they're already phone-shaped. */
.shots {
  display: grid;
  grid-template-columns: 1fr;
  gap: 18px;
}
.shot {
  margin: 0;
  text-align: center;
}
.shot img {
  width: 100%;
  max-width: 300px;
  height: auto;
  border-radius: var(--r-lg);
  border: 1px solid var(--border);
  box-shadow: var(--shadow-md);
  background: var(--surface);
}
.shot figcaption {
  margin-top: 10px;
  font-size: 0.85rem;
  color: var(--muted);
}

.welcome-cta {
  max-width: 380px;
  margin: 0 auto 34px;
  text-align: center;
}

.welcome-footer {
  border-top: 1px solid var(--border);
  padding-top: 22px;
  padding-bottom: 8px;
  font-size: 0.9rem;
}
.welcome-footer h2 {
  font-size: 0.75rem;
  font-weight: 650;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--faint);
  margin-bottom: 10px;
}
/* A second heading further down the footer (tech stack, after "About")
   needs space above it to separate from the paragraph before it; the
   first heading sits right against the footer's own top border and
   shouldn't get that same gap doubled onto it. */
.welcome-footer h2:not(:first-child) {
  margin-top: 14px;
}
.welcome-footer p {
  margin-bottom: 6px;
}
.welcome-footer ul {
  margin: 0 0 6px;
  padding-left: 1.1em;
}
.welcome-footer li {
  margin-bottom: 2px;
}
.welcome-footer a {
  color: var(--accent);
  font-weight: 550;
}
/* Set apart from the provenance lines above it: those are facts about the
   app, this is a caveat about relying on it, and it shouldn't read as just
   one more of them. Quiet rather than alarming — it's a family chore list,
   not a terms-of-service wall. */
.disclaimer {
  margin-top: 14px;
  padding-top: 14px;
  border-top: 1px solid var(--border);
  color: var(--faint);
  font-size: 0.82rem;
  max-width: 46em;
}

@media (min-width: 620px) {
  .shots {
    grid-template-columns: repeat(3, 1fr);
    gap: 14px;
  }
  .shot img {
    max-width: 100%;
  }
}

/* ---- desktop ---------------------------------------------------------- */

@media (min-width: 760px) {
  /* Above phone width there's no reason to pin navigation to the bottom
     edge — it becomes a normal row of pills directly under the app bar,
     and the content stops reserving space for a bar that isn't there. */
  .tabbar {
    position: static;
    background: transparent;
    backdrop-filter: none;
    -webkit-backdrop-filter: none;
    border-top: none;
    padding: 16px var(--gutter) 0;
  }
  .tabbar-inner {
    gap: 6px;
    padding: 4px;
    border-radius: 999px;
    background: var(--surface-sunken);
    border: 1px solid var(--border);
  }
  .tabbar button {
    flex-direction: row;
    gap: 7px;
    height: 40px;
    border-radius: 999px;
    font-size: 0.9rem;
  }
  .tabbar button .material-symbols-outlined { font-size: 20px; }
  .tabbar button.active {
    background: var(--surface);
    color: var(--text);
    box-shadow: var(--shadow-sm);
  }
  .tabbar button.active .material-symbols-outlined { color: var(--accent); }
  .content { padding-top: 20px; padding-bottom: 48px; }
  .fab { bottom: 24px; }
  .sheet-backdrop { align-items: center; padding: 24px; }
  .sheet {
    max-width: 640px;
    max-height: 86dvh;
    border-radius: var(--r-xl);
    animation: fade-in 0.18s ease;
  }
  .sheet-header::before { display: none; }
  .sheet-header { padding-top: 16px; }
}

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.001ms !important;
    transition-duration: 0.001ms !important;
  }
  button:active { transform: none; }
}

/* ---- icon font -------------------------------------------------------- */

.material-symbols-outlined {
  font-family: "Material Symbols Outlined";
  font-weight: normal;
  font-style: normal;
  font-size: 24px;
  line-height: 1;
  letter-spacing: normal;
  text-transform: none;
  display: inline-block;
  white-space: nowrap;
  word-wrap: normal;
  direction: ltr;
  -webkit-font-smoothing: antialiased;
  user-select: none;
  -webkit-user-select: none;
}
/* Hides every icon glyph until the font-ready check in index.html/login.html
   confirms the font is actually usable (or gives up and reveals them
   anyway — see that script's comment). Material Symbols are ligature
   *text*, so without this, a slow or blocked font load shows the raw icon
   name ("edit_note") instead of a blank tile — worse than no icon, since
   overflow: hidden then just clips it mid-word rather than hiding it. The
   icon's own tile background stays visible; only the glyph inside it does
   not, so this never collapses the layout. */
html.icons-loading .material-symbols-outlined {
  visibility: hidden;
}

/* Terminal fallback: the font is confirmed unusable — the Google Fonts
   stylesheet was blocked outright, or the font file never arrived. Since
   Material Symbols are ligature *text*, leaving it at that paints the
   literal name ("checklist", "dishwasher_gen") at full text width, which
   overflows the tab bar and every icon button and reads as a broken page.
   So clamp each glyph to a 1em box, shove the text out of it, and draw a
   neutral placeholder in its place — icon-only controls stay visible and
   tappable, and their title/aria-label still says what they do. Sized in
   em throughout, so each icon keeps whatever font-size its own rule set. */
html.icons-unavailable .material-symbols-outlined {
  position: relative;
  width: 1em;
  height: 1em;
  /* Contexts that clamp an icon's width for their own layout would leave the
     placeholder a rectangle — .chip-caret's max-width: 18px against a 24px
     font-size made the topbar caret 18x24. Pin both axes so it stays square
     wherever it lands. */
  max-width: 1em;
  max-height: 1em;
  overflow: hidden;
  /* Clears the longest ligature name at any icon size. */
  text-indent: -30em;
}
html.icons-unavailable .material-symbols-outlined::before {
  content: "";
  position: absolute;
  top: 0.12em;
  right: 0.12em;
  bottom: 0.12em;
  left: 0.12em;
  border: 0.085em solid currentColor;
  border-radius: 0.22em;
  opacity: 0.45;
}
