/* AIR Centre One. Colours, type and chrome follow aircentre.org; the values
   sit on shadcn/ui's custom property names so components read one vocabulary.
   Where the site's pairing fails WCAG AA the value is adjusted and says why.

   Breakpoints. Custom properties cannot stand in a media condition, so the
   viewport widths are named here and a new query takes one of them:
     phone  width <= 48rem   navigation moves to the tab bar at the bottom
     desk   width >= 64rem   the console's sidebar sits beside the content
   Older queries also hold 30, 35, 40, 43, 52, 54, 56, 60, 67.5, 72, 84 and
   100rem, each where one block's content stopped fitting; containers measure
   their own column. */

@font-face {
  font-family: "Roboto";
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url("fonts/roboto-latin-ext.woff2") format("woff2");
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF,
    U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020,
    U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

@font-face {
  font-family: "Roboto";
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url("fonts/roboto-latin.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
    U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193,
    U+2212, U+2215, U+FEFF, U+FFFD;
}

@font-face {
  font-family: "Lora";
  font-style: normal;
  font-weight: 600 700;
  font-display: swap;
  src: url("fonts/lora-latin-ext.woff2") format("woff2");
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF,
    U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020,
    U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

@font-face {
  font-family: "Lora";
  font-style: normal;
  font-weight: 600 700;
  font-display: swap;
  src: url("fonts/lora-latin.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
    U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193,
    U+2212, U+2215, U+FEFF, U+FFFD;
}

/* A subset holding only the glyphs ui.Icon is called with. A new icon means
   adding its name to icon_names (alphabetical) and running make icons:
   fonts.googleapis.com/css2?family=Material+Symbols+Outlined:opsz,wght,FILL,GRAD@24,400,0,0&icon_names=add_photo_alternate,arrow_forward,beach_access,bug_report,calendar_month,cancel,check,check_circle,chevron_left,chevron_right,close,content_copy,dashboard,directions_car,download,edit,edit_calendar,error,event_busy,expand_more,fact_check,feedback,flag,groups,history,home,inbox,info,inventory_2,lightbulb,link,lock,lock_open,login,logout,manage_accounts,menu,more_time,notification_important,notifications,open_in_new,person,person_add,person_off,restaurant,schedule,search,settings,today,undo,upload,verified,warning,weekend,wifi_off,work */
@font-face {
  font-family: "Material Symbols Outlined";
  font-style: normal;
  font-weight: 400;
  font-display: block;
  src: url("fonts/material-symbols-outlined.woff2") format("woff2");
}

/* Tokens. Brand values come from the site; the state colours pair each
   meaning with a surface and an ink that reach 4.5:1 on it in both schemes. */

:root {
  color-scheme: light dark;
  --radius-sm: 6px;
  --radius: 8px;
  --radius-lg: 10px;

  /* Spacing steps, named by their px at a 16px root. A value off the scale
     stays literal where it sits. */
  --space-2: 0.125rem;
  --space-4: 0.25rem;
  --space-6: 0.375rem;
  --space-8: 0.5rem;
  --space-10: 0.625rem;
  --space-12: 0.75rem;
  --space-14: 0.875rem;
  --space-16: 1rem;
  --space-20: 1.25rem;
  --space-24: 1.5rem;
  --space-32: 2rem;
  /* A target a thumb hits outdoors. */
  --touch: 44px;
  /* A card's inline padding, which its title, a list's outer cells and a
     stacked row's fields all start from. */
  --card-inset: var(--space-24);

  /* The logo's orange. On white it reads 2.7:1, short of AA even as large
     text; docs/spec/interface.md records the exception. */
  --brand: #f07d2f;
  --navy: #1a3a5c;
  --navy-deep: #0a192f;

  --background: #f3f5f8;
  --foreground: #101828;
  --card: #ffffff;
  --card-foreground: #101828;
  --popover: #ffffff;
  --popover-foreground: #101828;
  --primary: var(--brand);
  --secondary: #ffffff;
  --secondary-foreground: var(--navy);
  --muted: #eef1f5;
  --muted-foreground: #4a5568;
  --chevron: url("icons/chevron.svg");
  --accent: #fde6d8;
  --accent-foreground: #7a3208;
  --destructive: #b42318;
  --destructive-foreground: #ffffff;
  --border: #dde2e9;
  --border-strong: #b3bdca;
  /* A table row's divider. Dark --border on a card is 1.4:1, too faint to
     follow a row across a wide table. */
  --rule: var(--border);
  --input: #66768c;
  /* Orange marks the one action on a page and where you are, so links and
     the focus ring are ink blue: 7.5:1 on a card, 6.8:1 on the page. */
  --link: #0b5a85;
  --ring: #0b5a85;
  --heading: var(--navy);
  --selected: #e7eef6;
  --selected-foreground: #12385c;
  --row-hover: #f6f8fa;
  --tile: #f3f5f8;
  --nav-hover-line: rgb(255 255 255 / 0.4);

  --success: #1e6b45;
  --success-surface: #e3f4ea;
  --warning: #8a4b00;
  --warning-surface: #fdf0d9;
  --danger: #a3271d;
  --danger-surface: #fbe4e1;
  --info: #0b5a85;
  --info-surface: #dff0fa;
  --leave: #0b5f59;
  --leave-surface: #d8f3ef;
  --neutral-surface: #e4eaf1;

  --chrome: var(--navy);
  --chrome-deep: var(--navy-deep);
  --chrome-foreground: #ffffff;
  --chrome-muted: rgb(255 255 255 / 0.72);
  --chrome-line: rgb(255 255 255 / 0.12);

  --shadow-sm: none;
  --shadow-md: 0 8px 24px rgb(10 25 47 / 0.12);

  --font-body: "Roboto", system-ui, -apple-system, "Segoe UI", sans-serif;
  --font-heading: "Lora", Georgia, "Times New Roman", serif;

  --nav-height: 3.75rem;
  --header-height: 4rem;

  /* Layout. Gutters are fluid between a phone and a desk, while the gap
     between a page's blocks keeps its size at every width; the measure caps
     a reading column; the frame caps main in both shells, so the header
     holds still when someone moves between them. */
  --gutter: clamp(1rem, 0.5rem + 2vw, 2.5rem);
  --gap: var(--space-20);
  --measure: 44rem;
  --frame: 96rem;
  --aside: 24rem;
  --list-pane: 18rem;
  --rail: 4.5rem;
}

@media (prefers-color-scheme: dark) {
  :root {
    --background: #0b1626;
    --foreground: #e2e8f0;
    --card: #12223a;
    --card-foreground: #e2e8f0;
    --popover: #12223a;
    --popover-foreground: #e2e8f0;
    --secondary: transparent;
    --secondary-foreground: #e2e8f0;
    --muted: #1a2d48;
    --muted-foreground: #a7b4c6;
    --chevron: url("icons/chevron-dark.svg");
    --accent: #3a2618;
    --accent-foreground: #f8c7a6;
    --destructive: #f07167;
    --destructive-foreground: #0a192f;
    --border: #233955;
    --border-strong: #3a5478;
    --rule: var(--border-strong);
    --input: #7d8ea6;
    --link: #8cc8f0;
    --ring: #8cc8f0;
    /* White is 3.1:1 on the orange and 17:1 on the dark page. */
    --heading: #ffffff;
    --selected: #1c3352;
    --selected-foreground: #ffffff;
    --row-hover: #162a45;
    --tile: #0f1d33;

    --success: #86d9b0;
    --success-surface: #12382b;
    --warning: #f5c26b;
    --warning-surface: #3d2b0c;
    --danger: #f5a09a;
    --danger-surface: #46201d;
    --info: #8fd0f5;
    --info-surface: #0f3651;
    --leave: #7fe0d4;
    --leave-surface: #0f3e3a;
    --neutral-surface: #1f3556;

    --chrome: #0e2240;
    --chrome-deep: #061121;
    --chrome-line: rgb(255 255 255 / 0.1);

    --shadow-sm: none;
    --shadow-md: 0 8px 24px rgb(0 0 0 / 0.45);
  }

  .table-wrap {
    --scroll-shadow: rgb(0 0 0 / 0.5);
  }
}

*,
*::before,
*::after {
  box-sizing: border-box;
}

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

body {
  margin: 0;
  min-height: 100vh;
  min-height: 100dvh;
  display: flex;
  flex-direction: column;
  font-family: var(--font-body);
  font-size: 1rem;
  line-height: 1.5;
  background: var(--background);
  color: var(--foreground);
}

.shell {
  display: flex;
  flex-direction: column;
  flex: 1;
}

h1,
h2,
h3 {
  font-family: var(--font-heading);
  font-weight: 700;
  line-height: 1.2;
  color: var(--heading);
  margin: 0 0 var(--space-12);
  text-wrap: balance;
  /* A heading naming an address, as an invite's link does, breaks it rather
     than push a phone's page sideways. */
  overflow-wrap: break-word;
}

h1 {
  font-size: clamp(1.625rem, 1.35rem + 0.8vw, 1.875rem);
  letter-spacing: -0.01em;
}

h2 {
  font-size: 1.25rem;
  font-weight: 600;
}

h3 {
  font-size: 1.0625rem;
  font-weight: 600;
}

p {
  margin: 0 0 var(--space-16);
}

a {
  color: var(--link);
  text-underline-offset: 0.18em;
  text-decoration-thickness: 1px;
}

:focus-visible {
  outline: 3px solid var(--ring);
  outline-offset: 2px;
}

/* A control reached by Tab, forwards or back, scrolls clear of the sticky
   header, the phone's fixed bar and the leave plan's sticky Save bar rather
   than landing under any of them (WCAG 2.4.11). */
html {
  --actionbar-height: 4.5rem;
  scroll-padding-top: calc(var(--header-height) + 0.5rem);
}

/* The skip link's target is the page column, and a toast takes focus after
   a submit so a screen reader starts there. Neither is a control, so neither
   draws a ring. */
.page:focus-visible,
.toast:focus-visible {
  outline: none;
}

.icon {
  font-family: "Material Symbols Outlined";
  font-weight: normal;
  font-style: normal;
  font-size: 1.25em;
  line-height: 1;
  letter-spacing: normal;
  text-transform: none;
  display: inline-block;
  vertical-align: -0.25em;
  white-space: nowrap;
  direction: ltr;
  font-feature-settings: "liga";
  -webkit-font-smoothing: antialiased;
  flex: none;
}

.caption {
  margin: 0 0 var(--space-8);
  color: var(--muted-foreground);
  font-size: 0.875rem;
  font-weight: 600;
}

.visually-hidden,
.select-cell .check label {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

.skip-link {
  position: absolute;
  left: var(--space-16);
  top: -3.5rem;
  display: inline-flex;
  align-items: center;
  min-height: var(--touch);
  padding: var(--space-8) var(--space-16);
  background: var(--card);
  color: var(--foreground);
  border-radius: var(--radius);
  z-index: 10;
}

.skip-link:focus {
  top: var(--space-8);
}

/* Header and footer: the site's navy chrome. The current tab carries the
   header's one orange mark. The header's edge is main's content edge, so the
   brand and the avatar line up with the page below at every width. */

.shell-header {
  --edge: max(var(--gutter), (100% - var(--frame)) / 2 + var(--gutter));
  position: sticky;
  top: 0;
  z-index: 5;
  --header-gap: 2rem;
  display: flex;
  align-items: center;
  gap: var(--space-8) var(--header-gap);
  min-height: var(--header-height);
  padding: var(--space-8) max(var(--edge), env(safe-area-inset-right)) var(--space-8) max(var(--edge), env(safe-area-inset-left));
  background: var(--chrome);
  color: var(--chrome-foreground);
  border-bottom: 1px solid var(--chrome-line);
}

.shell-header :focus-visible {
  outline-color: var(--chrome-foreground);
}

.brand {
  display: flex;
  align-items: center;
  gap: var(--space-12);
  min-height: var(--touch);
  color: var(--chrome-foreground);
  text-decoration: none;
}

.brand img {
  height: 36px;
  width: auto;
}

.brand-name {
  font-family: var(--font-heading);
  font-size: 2.125rem;
  font-weight: 600;
  line-height: 1;
}

.shell-nav {
  display: flex;
  gap: var(--space-4);
  flex: 1;
}

.shell-nav a {
  display: inline-flex;
  align-items: center;
  gap: var(--space-6);
  min-height: var(--touch);
  padding: 0 var(--space-12);
  color: var(--chrome-muted);
  font-size: 0.8125rem;
  font-weight: 700;
  text-decoration: none;
  white-space: nowrap;
  border-radius: var(--radius-sm);
  transition: background-color 150ms ease-out, color 150ms ease-out;
}

.shell-nav a .icon {
  font-size: 1.25rem;
  opacity: 0.85;
}

.shell-nav a:hover,
.shell-nav a[aria-current="page"] {
  color: var(--chrome-foreground);
}

/* On a desk the tabs run the header's full height, so the underline sits on
   its bottom edge; hover's lighter line never reads as the current one. */
@media (width > 48rem) {
  .shell-header {
    padding-block: 0;
  }

  .shell-nav {
    align-self: stretch;
  }

  .shell-nav a {
    position: relative;
    min-height: var(--header-height);
    border-radius: 0;
  }

  .shell-nav a::after {
    content: "";
    position: absolute;
    left: 0;
    right: 0;
    bottom: 0;
    height: 3px;
    background: transparent;
    transition: background-color 150ms ease-out;
  }

  .shell-nav a:hover::after {
    background: var(--nav-hover-line);
  }

  .shell-nav a[aria-current="page"]::after {
    background: var(--brand);
  }
}

/* Sign-out keeps the right edge on setup too, where no nav fills the
   middle. */
.shell-header > form:last-child {
  margin-left: auto;
}

.shell-header .btn-signout {
  color: var(--chrome-foreground);
  border-color: rgb(255 255 255 / 0.35);
  background: transparent;
  min-height: 40px;
  padding: var(--space-6) var(--space-16);
  font-size: 0.9375rem;
}

.shell-header .btn-signout:hover {
  border-color: var(--brand);
  color: var(--chrome-foreground);
}

.avatar {
  flex: none;
  border-radius: 50%;
  object-fit: cover;
  background: var(--muted);
}

/* The avatar opens its panel under the header's right edge. */
.account-menu {
  position: relative;
  margin-left: auto;
}

/* The bell stands just left of the avatar and takes the right edge's auto
   margin from it. Their gap is fixed at every width and just wide enough
   to keep the count, which hangs 2px inside the bell's edge, clear of the
   avatar. */
.bell {
  position: relative;
  margin-left: auto;
}

.bell + .account-menu {
  margin-left: calc(var(--space-4) - var(--header-gap));
}

.bell > summary {
  position: relative;
  display: grid;
  place-items: center;
  width: var(--touch);
  height: var(--touch);
  list-style: none;
  cursor: pointer;
  border-radius: var(--radius-sm);
  color: var(--chrome-muted);
  transition: color 150ms ease-out;
}

/* via wraps the live face in a div; the glyph and the count are laid out by
   the summary's grid as before. */
.bell > summary > div,
.bell > summary > div > div {
  display: contents;
}

.bell > summary::-webkit-details-marker {
  display: none;
}


/* The count is the header's orange mark; dark digits keep it legible. */
.bell-count {
  position: absolute;
  top: calc(50% - 18px);
  right: 2px;
  min-width: 1.125rem;
  height: 1.125rem;
  padding: 0 var(--space-4);
  border-radius: 999px;
  background: var(--brand);
  color: #10141c;
  font-size: 0.6875rem;
  font-weight: 700;
  line-height: 1.125rem;
  text-align: center;
}

.bell-panel {
  width: min(24rem, calc(100vw - 2rem));
}

.bell-head {
  margin: 0 0 var(--space-4);
  padding: var(--space-8) var(--space-12) var(--space-12);
  border-bottom: 1px solid var(--border);
  font-weight: 700;
}

.bell-list {
  max-height: min(60vh, 28rem);
  overflow-y: auto;
  margin: 0;
  padding: 0;
  list-style: none;
}

.bell-panel .bell-item {
  display: grid;
  gap: var(--space-2);
  min-height: var(--touch);
  padding: var(--space-8) var(--space-12);
  color: var(--muted-foreground);
}

.bell-item.unread {
  color: inherit;
}

.bell-item.unread .bell-text::before {
  content: "";
  display: inline-block;
  width: 0.5rem;
  height: 0.5rem;
  margin-right: var(--space-8);
  border-radius: 50%;
  background: var(--brand);
  vertical-align: 0.1em;
}

/* The bell shows two lines of a notification; the notifications page shows it
   whole. */
.bell-text {
  display: -webkit-box;
  overflow: hidden;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 2;
  line-clamp: 2;
}

.bell-when {
  font-size: 0.8125rem;
  color: var(--muted-foreground);
}

.bell-empty {
  margin: 0;
  padding: var(--space-12);
  color: var(--muted-foreground);
}

.bell-panel .bell-all {
  justify-content: space-between;
  margin-top: var(--space-4);
  border-top: 1px solid var(--border);
  border-radius: 0 0 var(--radius-sm) var(--radius-sm);
  color: var(--link);
}

/* The trigger's chevron turns as the console menu's does. */
.account-menu > summary {
  display: flex;
  align-items: center;
  gap: var(--space-8);
  min-height: var(--touch);
  padding: 0 var(--space-4) 0 var(--space-6);
  list-style: none;
  cursor: pointer;
  border-radius: var(--radius-sm);
  color: var(--chrome-muted);
  transition: color 150ms ease-out;
}

/* The bell and the menu are nav links that open a panel: they light up the
   way a link does, and the one holding the page on show (Notifications,
   Preferences, My feedback) is current. */
.bell > summary:hover,
.bell[open] > summary,
.bell > summary.current,
.account-menu > summary:hover,
.account-menu[open] > summary,
.account-menu > summary.current {
  color: var(--chrome-foreground);
}

/* A phone marks it the way its bottom bar marks a tab, on the edge facing
   the page. */
.account-menu > summary {
  position: relative;
}

.bell > summary.current::after,
.account-menu > summary.current::after {
  content: "";
  position: absolute;
  left: 25%;
  right: 25%;
  bottom: 0;
  height: 3px;
  border-radius: 3px 3px 0 0;
  background: var(--brand);
}

/* On a desk they run the header's height and take the tabs' underline. */
@media (width > 48rem) {
  /* At the header's full height an outside ring runs off the top of the
     viewport and onto the page below, so it is drawn inside. */
  .shell-nav a:focus-visible,
  .bell > summary:focus-visible,
  .account-menu > summary:focus-visible {
    outline-offset: -6px;
  }

  .bell > summary,
  .account-menu > summary {
    height: var(--header-height);
    border-radius: 0;
  }

  .bell > summary::after,
  .account-menu > summary::after {
    content: "";
    position: absolute;
    left: 0;
    right: 0;
    bottom: 0;
    height: 3px;
    border-radius: 0;
    background: transparent;
    transition: background-color 150ms ease-out;
  }

  .bell > summary:hover::after,
  .bell[open] > summary::after,
  .account-menu > summary:hover::after,
  .account-menu[open] > summary::after {
    background: var(--nav-hover-line);
  }

  .bell > summary.current::after,
  .account-menu > summary.current::after {
    left: 0;
    right: 0;
    border-radius: 0;
    background: var(--brand);
  }
}

.account-name {
  max-width: 9rem;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-size: 0.9375rem;
  font-weight: 500;
}

.account-menu > summary .icon {
  transition: transform 150ms ease-out;
}

.account-menu[open] > summary .icon {
  transform: rotate(180deg);
}

/* Between the tab bar and a wide desk the header is tight: beside four or
   five links the name fits cut at 6rem, and six links need its width. It
   stays the trigger's accessible name, since the avatar's alt is empty. */
@media (48rem < width <= 67.5rem) {
  .account-name {
    max-width: 6rem;
  }

  .shell-header:has(.shell-nav > a:nth-of-type(6)) .account-name {
    position: absolute;
    width: 1px;
    height: 1px;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
  }
}

.account-menu > summary::-webkit-details-marker {
  display: none;
}

.account-menu > summary .avatar {
  box-shadow: 0 0 0 2px rgb(255 255 255 / 0.35);
  transition: box-shadow 150ms ease-out;
}


.account-panel,
.bell-panel {
  position: absolute;
  right: 0;
  top: calc(100% + var(--space-8));
  z-index: 6;
  display: grid;
  min-width: 15rem;
  max-width: calc(100vw - 2rem);
  padding: var(--space-8);
  background: var(--popover);
  color: var(--popover-foreground);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  box-shadow: var(--shadow-md);
}

.account-who {
  display: grid;
  gap: var(--space-2);
  margin: 0 0 var(--space-8);
  padding: var(--space-8) var(--space-12) var(--space-12);
  border-bottom: 1px solid var(--border);
  overflow-wrap: anywhere;
}

.account-who span {
  font-size: 0.875rem;
  color: var(--muted-foreground);
}

.account-panel a,
.account-panel button,
.bell-panel a,
.bell-panel button {
  display: flex;
  align-items: center;
  gap: var(--space-8);
  width: 100%;
  min-height: var(--touch);
  padding: 0 var(--space-12);
  border: 0;
  border-radius: var(--radius-sm);
  background: transparent;
  color: inherit;
  font: inherit;
  text-align: left;
  text-decoration: none;
  cursor: pointer;
}

/* The panels' entries are nav links standing in a column: muted until
   hovered, with the tabs' line turned to the left edge, as the console's
   sections mark theirs. */
/* Apart, two entries' bars never run into one line. */
.account-panel {
  gap: var(--space-4);
}

.account-panel a,
.account-panel button,
.bell-panel a,
.bell-panel button {
  position: relative;
  transition: color 150ms ease-out;
}

.account-panel a,
.account-panel button {
  color: var(--muted-foreground);
}

.account-panel a::before,
.account-panel button::before,
.bell-panel a::before,
.bell-panel button::before {
  content: "";
  position: absolute;
  top: 0;
  bottom: 0;
  left: 0;
  width: 3px;
  background: transparent;
  transition: background-color 150ms ease-out;
}

.account-panel a:hover,
.account-panel button:hover,
.account-panel a[aria-current="page"],
.bell-panel .bell-item:hover {
  color: var(--foreground);
}

/* The tabs' hover line is --nav-hover-line, 40% white over the header;
   mixed onto the chrome here, it shows the same colour on the panel. */
.account-panel a:hover::before,
.account-panel button:hover::before,
.bell-panel a:hover::before,
.bell-panel button:hover::before {
  background: color-mix(in srgb, #fff 40%, var(--chrome));
}

.account-panel a[aria-current="page"] {
  font-weight: 700;
}

.account-panel a[aria-current="page"]::before {
  background: var(--brand);
}

.account-panel :focus-visible,
.bell-panel :focus-visible {
  outline-color: var(--ring);
}


.person-link {
  display: inline-flex;
  align-items: center;
  gap: var(--space-8);
}

/* No component lists people outside a table: this is the one list, under
   the leave plans still missing. The avatar marks each person, so the list
   needs no bullet, and each link is a row of touch height. */
.person-list {
  list-style: none;
  margin: 0;
  padding: 0;
}

.person-list .person-link {
  min-height: var(--touch);
}

/* The avatar lines up with the heading's first line, which stays put when
   a narrow page stacks the heading's nav under it. */
.person-title {
  display: flex;
  align-items: flex-start;
  gap: var(--space-16);
}

/* min-width lets a heading that keeps its name on one line shrink beside
   the avatar instead of pushing the page wider than a phone. */
.person-title > .page-head {
  flex: 1;
  min-width: 0;
}

/* Frames. main is the frame and .page the content column; each is a size
   container, so the primitives below measure the column they sit in, never
   the viewport. In the app every child of .page is a reading column on the
   header's edge unless it lays panes or breaks out; in the console .page
   fills the width beside the section nav. */

main {
  container: frame / inline-size;
  width: 100%;
  max-width: var(--frame);
  margin: 0 auto;
  padding: var(--gap) var(--gutter) 3.5rem;
  flex: 1;
}

.page {
  container: page / inline-size;
  min-width: 0;
}

.shell-app .page {
  display: flex;
  flex-direction: column;
}

/* Every app page spaces its blocks by one gap, as Today does, so no two
   pages step down at different rhythms. */
.shell-app .page {
  gap: var(--gap);
}

.shell-app .page > * {
  width: 100%;
  max-width: var(--measure);
  margin-block: 0;
}

/* An empty toast or live slot would still take a gap. */
.shell-app .page > :empty {
  display: none;
}

/* A column less than a gap short of the frame's edge reads as misaligned,
   so a frame up to the measure plus one gap wide lets the column fill it. */
@container page (width < 45.25rem) {
  .shell-app .page > * {
    max-width: none;
  }
}

/* The back link sits as far above its heading as a console page's does, so
   the gap the flex column puts after it is taken back. */
.shell-app .page > .crumbs {
  margin-block: var(--space-8) calc(-1 * var(--gap));
}

/* The page's gap spaces the block after a breakout, so its last line, such
   as a calendar's legend, adds none of its own. */
.breakout > :last-child {
  margin-bottom: 0;
}

/* A page that lays panes or breaks out is a wide page: its blocks fill the
   frame to the header's edges, while its lead keeps the reading measure. */
.shell-app .page:has(> :is(.panes, .breakout)) > :not(.lead) {
  max-width: none;
}

/* A field in a form that breaks out, such as the leave plan's reason above
   its months, keeps the reading measure, as a lead does. */
.breakout form > .field {
  max-width: var(--measure);
}

/* A card of forms alone on a console page keeps the reading measure, as the
   app's form cards and every lead do, so a form ends on the lead's edge; a
   form beside its results is an aside, sized by the panes. A card standing
   in for a form, such as Deactivate on one's own account, keeps the same
   width. */
:is(.shell-console, .shell-super) :is(.page, .detail) > :is(.card:has(form), .card-narrow) {
  max-width: var(--measure);
}

/* A card of a month's figures keeps the same width, which holds three tiles
   and some slack, so on a wide page its tiles do not sit at one end of an
   empty card. */
:is(.shell-console, .shell-super) .detail > .card:has(> .figures) {
  max-width: var(--measure);
}

/* A cap a few rem short of the column's edge reads as a misaligned card, so a
   detail column too narrow to show the cap as a choice lets its cards fill
   it. */
@container page (width < 56rem) {
  :is(.shell-console, .shell-super) .detail > :is(.card:has(form), .card-narrow, .card:has(> .figures)) {
    max-width: none;
  }
}

/* A toast reports on the form below it, so it keeps that form's width; Export
   wraps its toast to hide it while a download starts. */
:is(.shell-console, .shell-super) .page > :is(.toast, :has(> .toast)):has(+ .card form) {
  max-width: var(--measure);
}

/* The footer sits in the content frame, so its rule and edges line up with
   the page and the header. main's frame width includes its gutters, so the
   footer's row takes them off. */
.shell-footer {
  padding: 0 var(--gutter);
  color: var(--muted-foreground);
  font-size: 0.875rem;
}

.shell-footer > div {
  display: grid;
  grid-template-columns: auto 1fr auto auto;
  align-items: center;
  gap: var(--space-12) var(--space-32);
  max-width: calc(var(--frame) - 2 * var(--gutter));
  margin: 3rem auto 0;
  padding: var(--space-16) 0;
  border-top: 1px solid var(--border);
}

.shell-footer p {
  margin: 0;
}

.footer-credit {
  display: flex;
  align-items: center;
  gap: var(--space-6);
}

.footer-rights,
.footer-via {
  display: inline-flex;
  align-items: center;
  gap: var(--space-6);
  height: 28px;
  padding: 0 var(--space-10);
  font-size: 0.8125rem;
  color: var(--muted-foreground);
  white-space: nowrap;
  text-decoration: none;
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-sm);
  transition: color 150ms ease-out, border-color 150ms ease-out;
}

.footer-rights:hover,
.footer-via:hover {
  color: var(--foreground);
  border-color: var(--muted-foreground);
}

/* The mark's slash keeps via's amber; on a light page it is darkened to
   stay visible. */
.via-mark {
  height: 0.75em;
  width: auto;
  aspect-ratio: 3 / 1;
}

.via-slash {
  fill: #c98a00;
}

.footer-about {
  grid-column: 3;
}

/* Both links are plain. The icon sits inline at the text's height, so the
   underline runs under it unbroken. The line matches the chips' height. */
.footer-about a,
.footer-feedback a {
  display: inline-block;
  line-height: 28px;
  white-space: nowrap;
  color: var(--link);
  text-underline-offset: 0.2em;
}

.footer-about a:hover,
.footer-feedback a:hover {
  text-decoration-thickness: 2px;
}

.footer-about .icon,
.footer-feedback .icon {
  display: inline;
  font-size: 1em;
  vertical-align: -0.125em;
}

@media (prefers-color-scheme: dark) {
  .via-mark {
    color: #fff;
  }

  .via-slash {
    fill: #ffbf00;
  }
}

/* On a phone the links sit on one row after the credit, at its right end as
   on a desk, each on a line a finger's height. */
@media (width <= 48rem) {
  .shell-footer > div {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-4) var(--space-32);
    padding: var(--space-12) 0;
  }

  .shell-footer .footer-about {
    margin-left: auto;
  }

  .footer-about a,
  .footer-feedback a {
    line-height: var(--touch);
  }

  .footer-rights,
  .footer-via {
    height: var(--touch);
  }
}

/* Until that row fits, the links lead, each over a chip and lined up with
   its edge. */
@media (width <= 35rem) {
  .shell-footer > div {
    display: grid;
    grid-template-columns: auto auto;
    justify-content: start;
    justify-items: start;
    gap: var(--space-4) var(--space-6);
  }

  .footer-credit {
    display: contents;
  }

  .footer-rights,
  .footer-via {
    order: 1;
  }

  .shell-footer .footer-about {
    grid-column: auto;
    margin-left: 0;
  }
}

/* Pages shown outside a shell: errors and the signed-out screen. */

/* The body is a 100dvh flex column; growing into it keeps the gradient to
   the bottom edge on a phone, where 100vh and the visible height differ. */
.standalone {
  flex: 1 0 auto;
  display: grid;
  place-items: center;
  min-height: 100dvh;
  padding: var(--space-24) var(--space-16);
  background: var(--chrome-deep);
  background-image: radial-gradient(ellipse at top, var(--navy) 0%, var(--chrome-deep) 65%);
}

.standalone-card {
  width: min(26rem, 100%);
  padding: var(--space-32) 1.75rem;
  text-align: center;
  background: var(--card);
  color: var(--card-foreground);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-md);
}

.standalone-logo {
  height: 72px;
  width: auto;
  margin-bottom: var(--space-8);
}

.standalone-brand {
  font-family: var(--font-heading);
  font-weight: 600;
  color: var(--muted-foreground);
  margin-bottom: var(--space-20);
}

.standalone h1 {
  font-size: 1.5rem;
}

.standalone .btn {
  width: 100%;
}

/* The card's padding alone sets the space under its last line, as above its
   logo. */
.standalone-card > :last-child {
  margin-bottom: 0;
}

/* Google's sign-in button: its own neutral fill, outline and G, which its
   branding asks for in place of the app's colours. Two classes, so it wins
   over the .btn rules later in the file. */
.btn.btn-google {
  gap: var(--space-12);
  background: #fff;
  color: #1f1f1f;
  border: 1px solid #747775;
  font-weight: 500;
}

.btn.btn-google:hover {
  background: #f2f2f2;
}

.btn-google svg {
  flex: none;
  width: 20px;
  height: 20px;
}

@media (prefers-color-scheme: dark) {
  .btn.btn-google {
    background: #131314;
    color: #e3e3e3;
    border-color: #8e918f;
  }

  .btn.btn-google:hover {
    background: #252526;
  }
}

.page-head {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-8) var(--space-24);
  margin-bottom: var(--gap);
}

.page-head :is(h1, h2) {
  margin: 0;
}

@media (width >= 64rem) {
  main {
    padding-top: var(--space-32);
  }
}

.card {
  container-type: inline-size;
  background: var(--card);
  color: var(--card-foreground);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  padding: var(--space-24) var(--card-inset);
  margin-bottom: var(--gap);
  box-shadow: var(--shadow-sm);
}

.card > :last-child {
  margin-bottom: 0;
}

.card > h2:first-child {
  margin-bottom: var(--space-16);
}

.lead {
  font-size: 1.0625rem;
  color: var(--muted-foreground);
  max-width: var(--measure);
  margin-bottom: var(--gap);
}

.muted {
  color: var(--muted-foreground);
}

.steps {
  padding-left: var(--space-20);
}

.steps li {
  margin-bottom: var(--space-12);
  padding-left: var(--space-4);
}

.steps li::marker {
  font-family: var(--font-heading);
  font-weight: 700;
  color: var(--brand);
}

.about-law {
  display: grid;
  grid-template-columns: minmax(10rem, max-content) 1fr;
  gap: var(--space-8) var(--space-24);
  margin: 0;
}

.about-law dt {
  font-weight: 600;
}

.about-law dd {
  margin: 0;
}

.faq {
  max-width: var(--measure);
  border-top: 1px solid var(--border);
}

.faq details {
  border-bottom: 1px solid var(--border);
}

.faq summary {
  justify-content: space-between;
  gap: var(--space-16);
  min-height: var(--touch);
  padding-block: var(--space-10);
  font-weight: 600;
}

.faq details p {
  margin: 0 0 var(--space-16);
}

@media (width <= 48rem) {
  .about-law {
    grid-template-columns: 1fr;
    gap: var(--space-2);
  }

  .about-law dd + dt {
    margin-top: var(--space-12);
  }
}

.actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-12);
  margin-top: var(--space-24);
}

/* The margin parts a group of buttons from what it follows; leading its
   card, it follows nothing. */
.card > .actions:first-child {
  margin-top: 0;
}

/* A download never re-renders the page, so its toast is in the page from
   the start, hidden until the press. It floats at the foot of the screen:
   in the flow it would move the button pressed or the rows under it as it
   shows and hides. Clicks pass through to what it covers. */
.download-toast {
  position: fixed;
  inset-inline: var(--gutter);
  bottom: var(--space-16);
  z-index: 4;
  max-width: 40rem;
  margin-inline: auto;
  pointer-events: none;
}

.download-toast:not(.shown) {
  display: none;
}

.download-toast .toast {
  margin: 0;
  box-shadow: var(--shadow-md);
}

/* An outcome from before a download press hides in place: the press does
   not reload the page, and a toast that collapsed would move what is under
   it. No component fits, since only a press without a reload needs it. */
.superseded {
  visibility: hidden;
}

.empty {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-8);
  margin: 0;
  padding: var(--space-8) var(--space-16);
  text-align: center;
  color: var(--muted-foreground);
}

.empty .icon {
  font-size: 2rem;
  opacity: 0.7;
}

/* A list with no rows keeps its title and says so in one line, so a page of
   empty queues stays short. */
.card > h2:first-child + .empty {
  flex-direction: row;
  align-items: flex-start;
  padding: 0;
  text-align: start;
}

/* The icon's line box is the text's, so it stays on the first line when the
   message wraps. */
.card > h2:first-child + .empty .icon {
  font-size: 1.25rem;
  line-height: 1.5rem;
}

/* Layout primitives. Cluster wraps a row; grid fills a row with equal tiles
   no narrower than --min; panes lays an aside beside a main pane when the
   page column has room and stacks them in source order when it has not;
   breakout lets a calendar leave the reading column; a list pane is the list
   half of a list-detail page and only exists on a wide screen. */

.cluster {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--cluster-gap, var(--space-12));
}

.toolbar {
  --cluster-gap: var(--gap);
  justify-content: space-between;
  align-items: flex-end;
  margin-bottom: var(--space-20);
}

.toolbar > * {
  margin: 0;
}

.grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(var(--min, 18rem), 100%), 1fr));
  gap: var(--gap);
}

.panes {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  column-gap: var(--gap);
  align-items: start;
}

.pane-aside,
.pane-main {
  container-type: inline-size;
  min-width: 0;
}

@container page (width >= 56rem) {
  .panes {
    grid-template-columns: var(--aside) minmax(0, 1fr);
  }

  .panes:has(> .pane-main:first-child) {
    grid-template-columns: minmax(0, 1fr) var(--aside);
  }

  .pane-aside.pinned {
    position: sticky;
    top: calc(var(--header-height) + var(--gap));
  }
}

.list-pane {
  display: none;
}

/* A month's days are 44px targets, seven to a row inside the pane's padding
   and the cells' borders, which an 18rem pane cut to 39px. */
.page:has(> .list-pane table) {
  --list-pane: 20.5rem;
}

.detail {
  container: page / inline-size;
  min-width: 0;
}

/* A page's crumbs open its column, so in the list-detail grid they would
   take the list's cell and push the detail a row down. */
.page:has(> .list-pane) > .crumbs {
  grid-column: 1 / -1;
  order: -2;
}

/* The list-detail grid needs the frame to hold the list beside a detail
   column at least as wide as the reading measure, after the console's nav. */
@container frame (width >= 60rem) {
  .shell-app .page:has(> .list-pane) {
    display: grid;
    grid-template-columns: var(--list-pane) minmax(0, 52rem);
    column-gap: var(--gap);
    align-items: start;
  }

  /* Each child takes its track, so the list pane's negative margins widen
     it to the track's edges rather than shift it. */
  .shell-app .page:has(> .list-pane) > * {
    width: auto;
    max-width: none;
  }

  .shell-app .list-pane {
    display: block;
  }
}

@container frame (width >= 84rem) {
  .shell-super .page:has(> .list-pane) {
    display: grid;
    grid-template-columns: var(--list-pane) minmax(0, 1fr);
    column-gap: var(--gap);
    align-items: start;
  }

  .shell-super .list-pane {
    display: block;
  }
}

/* The console's sidebar takes 13rem of the frame. From 75rem the detail
   beside the pane keeps 38rem or more, near the 40rem the app's grid leaves
   it, and a 1280px screen holds it. */
@container frame (width >= 75rem) {
  .shell-console .page:has(> .list-pane) {
    display: grid;
    grid-template-columns: var(--list-pane) minmax(0, 1fr);
    column-gap: var(--gap);
    align-items: start;
  }

  .shell-console .list-pane {
    display: block;
  }

  /* The team list moves to the same page of another person, so the header's
     person select would be a second control for it. */
  .shell-console .page:has(> .list-pane > a) form:has(#person-select) {
    display: none;
  }
}

/* The list follows the detail in the source, so the skip link and the
   keyboard reach the day or account first, not thirty links before it; the
   grid still draws it on the left. */
.list-pane {
  order: -1;
  position: sticky;
  top: calc(var(--header-height) + var(--gap));
  /* Same box the shell itself fills (.shell min-height above), so a short
     list still reaches as far down as a tall detail card beside it. */
  min-height: calc(100dvh - var(--header-height) - var(--gap) * 2);
  max-height: calc(100dvh - var(--header-height) - var(--gap) * 2);
  overflow-y: auto;
  /* The padding keeps focus rings inside the scroller's clip; the margin
     takes it back, so the list starts on the column's edge. */
  margin: 0 calc(-1 * var(--space-4));
  padding: var(--space-4);
}

.list-pane > .caption {
  margin: var(--space-4) 0 var(--space-8) var(--space-12);
}

/* Over a calendar the caption starts on the grid's edge, as its legend
   does; over a list it starts on the entries' text. */
.list-pane:has(.table-wrap) > .caption {
  margin-left: 0;
}

/* A pager standing in for the caption spans the calendar, its select taking
   the room between the arrows. */
.list-pane > .pager {
  margin-bottom: var(--space-8);
}

.list-pane > .pager > .pager-steps,
.list-pane .period-pick {
  flex: 1;
}

.list-pane .period-pick .input {
  flex: 1 1 auto;
}

/* The name takes the free space, so it starts beside the avatar. */
.list-pane > a {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-4) var(--space-8);
  min-height: var(--touch);
  padding: var(--space-6) var(--space-12);
  border-left: 3px solid transparent;
  border-radius: var(--radius-sm);
  color: var(--foreground);
  font-size: 0.9375rem;
  text-decoration: none;
  font-variant-numeric: tabular-nums;
}

.list-pane .list-label {
  flex: 1 1 auto;
  font-weight: 500;
}

.list-pane > a:hover {
  background: var(--muted);
  color: var(--heading);
}

.list-pane > a[aria-current="page"] {
  background: var(--selected);
  border-left-color: var(--brand);
  color: var(--selected-foreground);
  font-weight: 700;
}

.list-pane .badge {
  font-size: 0.75rem;
}

/* A badge takes the line under the name and starts on the name's edge, so
   the badges of a list line up whatever their length. */
.list-pane > a:has(> .badge) > .list-label {
  flex-basis: calc(100% - 24px - var(--space-8));
}

.list-pane > a > .avatar ~ .badge {
  margin-left: calc(24px + var(--space-8));
}

/* Buttons. 44px targets, for thumbs outdoors. */

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-8);
  min-height: var(--touch);
  padding: var(--space-10) var(--space-24);
  font: inherit;
  font-size: 1.1875rem;
  font-weight: 700;
  line-height: 1.2;
  border: 2px solid transparent;
  border-radius: var(--radius);
  cursor: pointer;
  text-decoration: none;
  transition: background-color 150ms ease-out, border-color 150ms ease-out, color 150ms ease-out, transform 100ms ease-out;
}

.btn[hidden] {
  display: none;
}

.btn:active:not(:disabled) {
  transform: translateY(1px);
}

.btn:disabled {
  opacity: 0.5;
  cursor: not-allowed;
}

/* The primary button is outlined, with orange words. */
.btn-primary {
  background: transparent;
  color: var(--primary);
  border-color: var(--primary);
}

.btn-primary:hover:not(:disabled) {
  background: var(--accent);
}

/* A step below the orange primary in size and weight, so the one main
   action leads the page while the target stays 44px. */
.btn-secondary {
  background: var(--secondary);
  color: var(--secondary-foreground);
  border-color: var(--input);
  padding-inline: var(--space-16);
  font-size: 1rem;
  font-weight: 500;
}

.btn-secondary:hover:not(:disabled) {
  border-color: var(--link);
  color: var(--link);
}

.btn-ghost {
  background: transparent;
  color: inherit;
  padding-inline: var(--space-12);
}

.btn-ghost:hover:not(:disabled) {
  background: var(--muted);
}

.btn-danger {
  background: var(--destructive);
  color: var(--destructive-foreground);
}

.btn-icon {
  min-width: var(--touch);
  padding: var(--space-8);
}

.field {
  display: flex;
  flex-direction: column;
  gap: var(--space-6);
  margin-bottom: var(--space-20);
}

.field label,
fieldset legend {
  font-weight: 500;
}

.invite-link-row {
  display: flex;
  align-items: flex-end;
  gap: var(--space-12);
}

.invite-link-row .field {
  flex: 1;
  min-width: 0;
  margin-bottom: 0;
}

fieldset {
  border: 0;
  padding: 0;
  margin: 0 0 var(--space-20);
  min-width: 0;
}

fieldset legend {
  margin-bottom: var(--space-8);
  padding: 0;
}

/* 16px whatever the text around it, a table's 14px included: iOS zooms the
   page into any smaller field it focuses. */
.input {
  width: 100%;
  min-height: var(--touch);
  padding: var(--space-8) var(--space-12);
  font: inherit;
  font-size: 1rem;
  color: var(--foreground);
  background: var(--card);
  border: 1px solid var(--input);
  border-radius: var(--radius);
  transition: border-color 150ms ease-out;
}

.input:hover {
  border-color: var(--foreground);
}

/* The native arrow ignores padding-right and differs per system, so every
   select draws the same chevron, centred on its first line: a box that grows
   to hold a row inside it keeps the chevron beside the value. */
select.input {
  padding-right: 2.25rem;
  appearance: none;
  cursor: pointer;
  background: var(--card) var(--chevron) no-repeat right var(--space-8) top
    calc(var(--touch) / 2 - 0.625rem - 1px) / 1.25rem;
}

/* A date or time field moves focus between its parts and its calendar
   button, inside the browser's shadow tree; Chromium does not count that as
   keyboard focus, so the ring follows focus and focus-within. */
.input:is(:focus, :focus-within) {
  outline: 3px solid var(--ring);
  outline-offset: 2px;
}

.textarea {
  resize: vertical;
  line-height: 1.4;
}

.input[aria-invalid="true"] {
  border: 2px solid var(--destructive);
}

/* A native box takes no border, so a refused one is ringed, and the focus
   ring still shows on the box that has focus. */
.checkbox[aria-invalid="true"]:not(:focus-visible) {
  outline: 2px solid var(--destructive);
  outline-offset: 1px;
}

/* A segmented choice is radios drawn as joined buttons. The radio stays in
   the page, so Tab and the arrow keys reach it and the form posts it; its
   face shows the state. The chosen face thickens its border with an inset
   shadow, which leaves the row's width alone. */
.segmented {
  display: flex;
  flex-wrap: wrap;
}

.segment {
  position: relative;
  flex: 1 1 0;
  min-width: max-content;
}

.segment-input {
  position: absolute;
  inset: 0;
  opacity: 0;
  margin: 0;
}

.segment-face {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-8);
  min-height: var(--touch);
  padding: var(--space-8) var(--space-16);
  background: var(--card);
  border: 1px solid var(--input);
  cursor: pointer;
  transition: background-color 150ms ease-out, border-color 150ms ease-out;
}

.segment + .segment .segment-face {
  margin-left: -1px;
}

.segment:first-child .segment-face {
  border-radius: var(--radius) 0 0 var(--radius);
}

.segment:last-child .segment-face {
  border-radius: 0 var(--radius) var(--radius) 0;
}

.segment:hover .segment-face {
  position: relative;
  border-color: var(--foreground);
}

.segment-input:checked + .segment-face {
  position: relative;
  z-index: 1;
  background: var(--selected);
  color: var(--selected-foreground);
  border-color: var(--link);
  box-shadow: inset 0 0 0 1px var(--link);
  font-weight: 500;
}

/* The ring has its own box, rounded at every corner like a lone control's:
   an outline on the face follows its square corners at the seam. Its inset
   is the global ring's width plus its offset. */
.segment-input:focus-visible + .segment-face {
  position: relative;
  z-index: 2;
}

.segment-input:focus-visible + .segment-face::after {
  content: "";
  position: absolute;
  inset: -5px;
  border: 3px solid var(--ring);
  border-radius: calc(var(--radius) + 5px);
  pointer-events: none;
}

.segment-input[aria-invalid="true"] + .segment-face {
  border-color: var(--destructive);
}

.flag {
  flex: none;
  border-radius: 2px;
  box-shadow: 0 0 0 1px rgb(0 0 0 / 0.15);
}

/* The picture field: the avatar in use beside the button that replaces it.
   The file input sits inside the button, so the button shows its focus. */
.picture-field {
  display: grid;
  grid-template-columns: auto 1fr;
  column-gap: var(--space-16);
  align-items: start;
}

.picture-field > .avatar {
  grid-row: span 3;
}

.picture-field > :not(.avatar) {
  grid-column: 2;
  justify-self: start;
}

.file-field {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: var(--space-6);
}

.field-label {
  margin: 0;
  font-weight: 500;
}

.file-button:has(:focus-visible) {
  outline: 3px solid var(--ring);
  outline-offset: 2px;
}

.file-button:has([aria-invalid="true"]) {
  border-color: var(--destructive);
}

.setup-groups h2 {
  margin-top: 0;
}

/* Setup's two groups stand side by side once each still has a form's
   width, and the page around them widens to hold both. */
@media (width >= 64rem) {
  .shell-app .page:has(> .setup-card) > * {
    max-width: 64rem;
  }

  .setup-groups {
    display: grid;
    grid-template-columns: 1fr 1fr;
    column-gap: 3rem;
  }
}

.field-hint {
  margin: 0;
  font-size: 0.875rem;
  color: var(--muted-foreground);
}

.badge + .field-hint {
  margin-top: var(--space-6);
}

/* Hints between controls, outside any field: a correction form's note on
   empty hours before the reason field. */
form > .field-hint + .field,
form > .field-hint + .check {
  margin-top: var(--space-16);
}

.time-grid + .check {
  margin-bottom: var(--space-8);
}

.field-error {
  display: flex;
  align-items: flex-start;
  gap: var(--space-6);
  margin: 0;
  font-size: 0.875rem;
  font-weight: 500;
  color: var(--destructive);
}

/* The icon sits on the first line of a message that wraps, as a toast's does. */
.field-error > .icon {
  margin-top: 0.1em;
}

.check {
  position: relative;
  display: flex;
  align-items: center;
  gap: var(--space-12);
  min-height: var(--touch);
}

/* The label covers the whole 44px row, box included, so a tap anywhere on
   the row toggles the box. */
.check > label {
  cursor: pointer;
}

.check > label::before {
  content: "";
  position: absolute;
  inset: 0;
}

.checkbox {
  flex: none;
  width: 1.25rem;
  height: 1.25rem;
  margin: 0;
  accent-color: var(--link);
}

.reminder {
  display: grid;
  grid-template-columns: 1fr auto;
  align-items: center;
  gap: var(--space-12);
  border-bottom: 1px solid var(--border);
  padding: var(--space-12) 0;
}

.reminder:last-child {
  border-bottom: 0;
}

.reminder .field {
  flex-direction: row;
  align-items: center;
  gap: var(--space-8);
  margin: 0;
}

.reminder .field .input {
  width: 8rem;
}

.reminder .field label {
  font-size: 0.8125rem;
  color: var(--muted-foreground);
}

/* In a narrow card the hour drops under its reminder and starts where the
   reminder's words do, past the box and its gap, so the words keep the
   row's width instead of wrapping to three lines beside the select. */
@container (width < 30rem) {
  .reminder {
    grid-template-columns: 1fr;
    gap: 0;
  }

  .reminder .field {
    padding-left: calc(1.25rem + var(--space-12));
  }
}

/* A row's dialog sits inside the table, so it resets the text the table
   sets: tabular figures widen Lora's spaces, and the cells' size is a step
   below every other dialog's. */
.dialog {
  font-size: 1rem;
  line-height: 1.5;
  font-variant-numeric: normal;
  text-align: start;
  width: min(32rem, calc(100vw - 2rem));
  padding: 0;
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  background: var(--popover);
  color: var(--popover-foreground);
  box-shadow: 0 10px 30px rgb(10 25 47 / 0.35);
}

.dialog::backdrop {
  background: rgb(10 25 47 / 0.55);
  backdrop-filter: blur(4px);
}

.dialog-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-16);
  padding: var(--space-16) var(--space-16) 0 var(--space-24);
}

/* Balanced lines, and pretty ones avoiding a short last line, break a row's
   name in half beside the close button; the title fills its first line
   instead. An address too long for the line breaks inside it, so the close
   button stays in the dialog. */
.dialog-head h2 {
  margin: 0;
  text-wrap: wrap;
  overflow-wrap: anywhere;
}

.dialog-body {
  padding: var(--space-16) var(--space-24) var(--space-24);
}

.dialog .actions {
  justify-content: flex-end;
}

/* A phone's dialog is too narrow for two long labels side by side: the
   buttons share a row while both fit on one line, and each takes a row of
   its own once either would wrap. A label longer than a row of its own wraps
   inside its button rather than push it past the dialog's edge. */
@media (width <= 48rem) {
  .dialog .actions > .btn {
    flex: 1 1 auto;
    white-space: normal;
    text-align: center;
    text-wrap: balance;
  }
}

/* Tables: dense, tabular figures, legible on a desk screen. */

/* Wider than its column the table scrolls sideways; the edge shadows say so
   where scrollbars are hidden. The card-coloured layers scroll with the
   content and cover the shadows at either end. */
/* Positioned so it is the containing block of the visually hidden text in
   its cells: an absolute box escapes the overflow clip of a scroller that is
   not its containing block, and widens the page instead. */
.table-wrap {
  --scroll-shadow: rgb(10 25 47 / 0.16);
  position: relative;
  overflow-x: auto;
  background:
    linear-gradient(to right, var(--card) 40%, transparent) left / 3rem 100% no-repeat local,
    linear-gradient(to left, var(--card) 40%, transparent) right / 3rem 100% no-repeat local,
    linear-gradient(to right, var(--scroll-shadow), transparent) left / 1rem 100% no-repeat scroll,
    linear-gradient(to left, var(--scroll-shadow), transparent) right / 1rem 100% no-repeat scroll,
    var(--card);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  margin-bottom: var(--space-20);
  box-shadow: var(--shadow-sm);
  container-type: inline-size;
}

.table {
  width: 100%;
  border-collapse: collapse;
  font-size: 0.875rem;
  font-variant-numeric: tabular-nums;
  color: var(--card-foreground);
}

/* A list's title, an h2 inside the table's frame, takes a card title's size
   and inset, so a list and a form on one page title alike. */
.table-title {
  margin: 0;
  padding: var(--space-24) var(--card-inset) var(--space-12);
}

/* A column of figures lines up at its end, where the digits agree. */
.table th.num,
.table td.num {
  text-align: end;
}

/* A cell's last paragraph ends the cell, so a note stands no taller than a
   name. */
.table td p:last-child {
  margin-bottom: 0;
}

/* A date never splits, even in a cell that wraps anywhere. */
.table time {
  white-space: nowrap;
}

.table th,
.table td {
  padding: var(--space-10) var(--space-14);
  text-align: left;
  white-space: nowrap;
  border-top: 1px solid var(--rule);
  vertical-align: top;
}

/* A list's outer cells take the card's inset, so its title, column heads
   and rows start on one edge, and a list under the page's own heading lines
   up with the cards beside it. :where keeps the rule below the stacked
   blocks, which pad the row instead, and the calendar, which pads none. */
:where(.table-wrap .table) :is(th, td):first-child {
  padding-left: var(--card-inset);
}

:where(.table-wrap .table) :is(th, td):last-child {
  padding-right: var(--card-inset);
}

/* Headings wrap so a wordy column (Portuguese runs long) takes the width of
   its values, not of its name. */
.table thead th {
  position: sticky;
  top: 0;
  background: var(--card);
  color: var(--muted-foreground);
  font-weight: 600;
  font-size: 0.8125rem;
  line-height: 1.25;
  white-space: normal;
  vertical-align: bottom;
  border-bottom: 1px solid var(--border-strong);
}

.table tbody tr:hover {
  background: var(--row-hover);
}

.table tbody tr:last-child td {
  border-bottom: 0;
}

/* The last column holds whatever runs long, a note or a stamp summary, so
   it wraps instead of pushing the table into a sideways scroll. */
.table td:last-child {
  white-space: normal;
  min-width: 12rem;
}

/* A trailing button, disclosure, badge, date or figure is as wide as
   itself; the floor is for a note. */
.table td:last-child:is(.num, :has(form, details, .badge, > time)) {
  min-width: 0;
}

/* The unheaded column a row keeps for its actions ends on the card's inset,
   so its buttons line up with the controls above the table. */
.table td[data-label=""]:last-child {
  text-align: end;
  text-wrap: balance;
}

.table td[data-label=""]:last-child :is(.actions, form):not(dialog *) {
  justify-content: flex-end;
}

/* A prose value (a holiday's name, a correction's reason) wraps where it
   sits, so a narrow column fits without a sideways scroll. */
.table td:has(> .cell-wrap) {
  white-space: normal;
  min-width: 7rem;
}

/* Labelled stamps wrap between stamps, never inside one. */
.table td:has(> .day-times) {
  white-space: normal;
  min-width: 10rem;
}

/* A link alone in a cell, wrapping or not, keeps the row's height as its tap
   target; the negative margin leaves the row where it was. The display sits
   under :where so a person link keeps its own. */
.table td > a:only-child,
.table td > .cell-wrap:only-child > a:only-child {
  padding-block: var(--space-10);
  margin-block: -0.625rem;
}

:where(.table td > a:only-child, .table td > .cell-wrap:only-child > a:only-child) {
  display: inline-block;
}

/* A name wraps inside a capped column, so an 81-character name takes three
   lines instead of the width of the columns after it. The floor holds a
   two-word name and its avatar on one line. */
.table td:has(> .person-link) {
  white-space: normal;
  min-width: 12rem;
  max-width: 18rem;
}

/* The avatar centres on the name's line, alone in a cell or in a list of
   names. */
.table td a.person-link {
  overflow-wrap: anywhere;
  vertical-align: middle;
}

/* In a row of buttons, a cell of text drops its first line onto their
   centre, which a tall row's top alignment would leave hanging above their
   labels. 40px is a desk row's button, set under .table .btn. :where leaves
   the stacked blocks' padding in charge. */
:where(.table tbody tr:has(.btn)) > td:not(:has(.btn)) {
  padding-top: calc(var(--space-10) + (40px - 1lh) / 2);
}

/* A reflowed table: each row a bordered block with the first cell as its
   title. The other cells are fields, a label beside a value; a form cell
   takes its own line. A zero leaves view but stays in the tree, as does the
   head, for a screen reader. A wide table's rows need about 60rem, which the
   console's column reaches at a 1280px screen; narrower, it stacks rather
   than scroll a row's columns or buttons out of view. */
@container (width < 60rem) {
  .reflow .table,
  .reflow .table tbody,
  .reflow .table tr,
  .reflow .table td {
    display: block;
    white-space: normal;
  }

  /* A stacked cell is sized by the block, so a column's minimum or maximum
     width would only push it past the edge or cut it short. */
  .reflow .table td {
    flex: 1 1 20rem;
    min-width: 0;
    max-width: none;
  }

  /* A block is only the column's width, so its buttons wrap again. */
  .reflow .table .actions:not(dialog *) {
    flex-wrap: wrap;
  }

  .reflow .table thead {
    position: absolute;
    width: 1px;
    height: 1px;
    overflow: hidden;
    clip-path: inset(50%);
  }

  /* A block's fields sit two to a line where two of 20rem fit, so every row
     of a table puts the same field in the same place; a field alone on its
     line takes the whole width. Two fields on a line share a baseline. */
  .reflow .table tr {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    column-gap: var(--space-24);
    padding: var(--space-12) var(--card-inset) var(--space-16);
    border-top: 1px solid var(--border);
  }

  .reflow .table tbody tr:hover {
    background: transparent;
  }

  .reflow .table td {
    padding: var(--space-4) 0;
    border: 0;
  }

  .reflow .table td:first-child,
  .reflow .table td:has(form),
  .reflow .table td[data-label=""] {
    flex-basis: 100%;
  }

  .reflow .table td[data-label=""] {
    text-align: start;
  }

  .reflow .table td[data-label=""] :is(.actions, form):not(dialog *) {
    justify-content: flex-start;
  }

  .reflow .table td:first-child {
    padding-bottom: var(--space-6);
    font-size: 1rem;
    font-weight: 700;
    color: var(--heading);
  }

  .reflow .table td:not(:first-child)::before {
    content: attr(data-label);
    display: inline;
    font-size: 0.75rem;
    font-weight: 600;
    color: var(--muted-foreground);
  }

  .reflow .table td:empty,
  .reflow .table td:has(> .cell-wrap:empty) {
    display: none;
  }

  /* A cell of buttons needs no label beside its own verbs, nor does the
     unheaded column a row keeps for its actions. */
  .reflow .table td:not(:first-child):has(form)::before,
  .reflow .table td[data-label=""]::before {
    content: none;
  }

  /* A field is its label beside its value, the labels in one column, so the
     eye runs down them; parts of a value stack beside the label. A value
     wraps anywhere, since a long address would otherwise push the block past
     its edge. :where keeps the rule weak enough for a title cell to undo. */
  .reflow .table td:where(:not(:first-child, :empty, [data-label=""], :has(form, > .cell-wrap:empty))) {
    display: grid;
    grid-template-columns: 7rem minmax(0, 1fr);
    column-gap: var(--space-8);
    align-items: baseline;
    justify-items: start;
    overflow-wrap: anywhere;
  }

  .reflow .table td:where(:not(:first-child, :empty, [data-label=""], :has(form, > .cell-wrap:empty))) > * {
    grid-column: 2;
  }

  /* On a touch screen a field's padding is what a 44px target adds to a
     line, and the field's link or list of days spans it. A field of text and
     a field of links then keep one pitch, and no target reaches past its
     field. */
  @media (width <= 48rem) {
    .reflow .table td:not(:first-child) {
      padding-block: calc((var(--touch) - 1lh) / 2);
    }

    .reflow .table td:not(:first-child) > a:only-child,
    .reflow .table td:not(:first-child) > .cell-wrap:only-child > a:only-child {
      margin-block: calc((1lh - var(--touch)) / 2);
    }

    .reflow .table td:not(:first-child) .attest-days:first-child {
      margin-top: calc((1lh - var(--touch)) / 2);
    }

    .reflow .table td:not(:first-child) .attest-days:last-child {
      margin-bottom: calc((1lh - var(--touch)) / 2);
    }
  }

  /* An avatar has no baseline, so its name and label centre on each other. */
  .reflow .table td:has(> .person-link)::before,
  .reflow .table td > .person-link {
    align-self: center;
  }

  .reflow .table td.num {
    text-align: start;
    font-variant-numeric: tabular-nums;
  }

  /* A long badge wraps, since the value column is narrower than its words. */
  .reflow .table td .badge {
    white-space: normal;
  }

  .reflow .table td[data-zero] {
    position: absolute;
    width: 1px;
    height: 1px;
    overflow: hidden;
    clip-path: inset(50%);
  }

  /* A field holds its targets whole, so none reaches a neighbouring field. */
  .reflow .table td > a:only-child,
  .reflow .table td > .cell-wrap:only-child > a:only-child {
    display: inline-flex;
    align-items: center;
    padding-block: 0;
    margin-block: 0;
  }

  .reflow .table td > form {
    margin-top: var(--space-8);
  }

  .reflow .table form:not(dialog *) .input {
    min-width: 0;
    width: 100%;
  }

  .reflow .table form:not(dialog *) .field {
    flex: 1 1 12rem;
  }
}

/* A table whose rows fit in 43rem stacks the same way below it, rather than
   scroll part of a row out of view; the app's column and the console's at a
   1024px screen are just wider. TestTables_stackTheWayWideTablesReflow in
   test/lint/ holds this block to the reflow block above. */
@container (width < 43rem) {
  .stack .table,
  .stack .table tbody,
  .stack .table tr,
  .stack .table td {
    display: block;
    white-space: normal;
  }

  /* A stacked cell is sized by the block, so a column's minimum or maximum
     width would only push it past the edge or cut it short. */
  .stack .table td {
    flex: 1 1 20rem;
    min-width: 0;
    max-width: none;
  }

  /* A block is only the column's width, so its buttons wrap again. */
  .stack .table .actions:not(dialog *) {
    flex-wrap: wrap;
  }

  .stack .table thead {
    position: absolute;
    width: 1px;
    height: 1px;
    overflow: hidden;
    clip-path: inset(50%);
  }

  /* A block's fields sit two to a line where two of 20rem fit, so every row
     of a table puts the same field in the same place; a field alone on its
     line takes the whole width. Two fields on a line share a baseline. */
  .stack .table tr {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    column-gap: var(--space-24);
    padding: var(--space-12) var(--card-inset) var(--space-16);
    border-top: 1px solid var(--border);
  }

  .stack .table tbody tr:hover {
    background: transparent;
  }

  .stack .table td {
    padding: var(--space-4) 0;
    border: 0;
  }

  .stack .table td:first-child,
  .stack .table td:has(form),
  .stack .table td[data-label=""] {
    flex-basis: 100%;
  }

  .stack .table td[data-label=""] {
    text-align: start;
  }

  .stack .table td[data-label=""] :is(.actions, form):not(dialog *) {
    justify-content: flex-start;
  }

  .stack .table td:first-child {
    padding-bottom: var(--space-6);
    font-size: 1rem;
    font-weight: 700;
    color: var(--heading);
  }

  .stack .table td:not(:first-child)::before {
    content: attr(data-label);
    display: inline;
    font-size: 0.75rem;
    font-weight: 600;
    color: var(--muted-foreground);
  }

  .stack .table td:empty,
  .stack .table td:has(> .cell-wrap:empty) {
    display: none;
  }

  /* A cell of buttons needs no label beside its own verbs, nor does the
     unheaded column a row keeps for its actions. */
  .stack .table td:not(:first-child):has(form)::before,
  .stack .table td[data-label=""]::before {
    content: none;
  }

  /* A field is its label beside its value, the labels in one column, so the
     eye runs down them; parts of a value stack beside the label. A value
     wraps anywhere, since a long address would otherwise push the block past
     its edge. :where keeps the rule weak enough for a title cell to undo. */
  .stack .table td:where(:not(:first-child, :empty, [data-label=""], :has(form, > .cell-wrap:empty))) {
    display: grid;
    grid-template-columns: 7rem minmax(0, 1fr);
    column-gap: var(--space-8);
    align-items: baseline;
    justify-items: start;
    overflow-wrap: anywhere;
  }

  .stack .table td:where(:not(:first-child, :empty, [data-label=""], :has(form, > .cell-wrap:empty))) > * {
    grid-column: 2;
  }

  /* On a touch screen a field's padding is what a 44px target adds to a
     line, and the field's link or list of days spans it. A field of text and
     a field of links then keep one pitch, and no target reaches past its
     field. */
  @media (width <= 48rem) {
    .stack .table td:not(:first-child) {
      padding-block: calc((var(--touch) - 1lh) / 2);
    }

    .stack .table td:not(:first-child) > a:only-child,
    .stack .table td:not(:first-child) > .cell-wrap:only-child > a:only-child {
      margin-block: calc((1lh - var(--touch)) / 2);
    }

    .stack .table td:not(:first-child) .attest-days:first-child {
      margin-top: calc((1lh - var(--touch)) / 2);
    }

    .stack .table td:not(:first-child) .attest-days:last-child {
      margin-bottom: calc((1lh - var(--touch)) / 2);
    }
  }

  /* An avatar has no baseline, so its name and label centre on each other. */
  .stack .table td:has(> .person-link)::before,
  .stack .table td > .person-link {
    align-self: center;
  }

  .stack .table td.num {
    text-align: start;
    font-variant-numeric: tabular-nums;
  }

  /* A long badge wraps, since the value column is narrower than its words. */
  .stack .table td .badge {
    white-space: normal;
  }

  .stack .table td[data-zero] {
    position: absolute;
    width: 1px;
    height: 1px;
    overflow: hidden;
    clip-path: inset(50%);
  }

  /* A field holds its targets whole, so none reaches a neighbouring field. */
  .stack .table td > a:only-child,
  .stack .table td > .cell-wrap:only-child > a:only-child {
    display: inline-flex;
    align-items: center;
    padding-block: 0;
    margin-block: 0;
  }

  .stack .table td > form {
    margin-top: var(--space-8);
  }

  .stack .table form:not(dialog *) .input {
    min-width: 0;
    width: 100%;
  }

  .stack .table form:not(dialog *) .field {
    flex: 1 1 12rem;
  }
}

/* A table whose rows fit in 36rem stacks the same way below it, so it stays
   a table on a person's pages, whose column beside the team list is 42rem at
   a 1280px screen. TestTables_stackTheWayWideTablesReflow holds this block to
   the reflow block too. */
@container (width < 36rem) {
  .narrow .table,
  .narrow .table tbody,
  .narrow .table tr,
  .narrow .table td {
    display: block;
    white-space: normal;
  }

  /* A stacked cell is sized by the block, so a column's minimum or maximum
     width would only push it past the edge or cut it short. */
  .narrow .table td {
    flex: 1 1 20rem;
    min-width: 0;
    max-width: none;
  }

  /* A block is only the column's width, so its buttons wrap again. */
  .narrow .table .actions:not(dialog *) {
    flex-wrap: wrap;
  }

  .narrow .table thead {
    position: absolute;
    width: 1px;
    height: 1px;
    overflow: hidden;
    clip-path: inset(50%);
  }

  /* A block's fields sit two to a line where two of 20rem fit, so every row
     of a table puts the same field in the same place; a field alone on its
     line takes the whole width. Two fields on a line share a baseline. */
  .narrow .table tr {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    column-gap: var(--space-24);
    padding: var(--space-12) var(--card-inset) var(--space-16);
    border-top: 1px solid var(--border);
  }

  .narrow .table tbody tr:hover {
    background: transparent;
  }

  .narrow .table td {
    padding: var(--space-4) 0;
    border: 0;
  }

  .narrow .table td:first-child,
  .narrow .table td:has(form),
  .narrow .table td[data-label=""] {
    flex-basis: 100%;
  }

  .narrow .table td[data-label=""] {
    text-align: start;
  }

  .narrow .table td[data-label=""] :is(.actions, form):not(dialog *) {
    justify-content: flex-start;
  }

  .narrow .table td:first-child {
    padding-bottom: var(--space-6);
    font-size: 1rem;
    font-weight: 700;
    color: var(--heading);
  }

  .narrow .table td:not(:first-child)::before {
    content: attr(data-label);
    display: inline;
    font-size: 0.75rem;
    font-weight: 600;
    color: var(--muted-foreground);
  }

  .narrow .table td:empty,
  .narrow .table td:has(> .cell-wrap:empty) {
    display: none;
  }

  /* A cell of buttons needs no label beside its own verbs, nor does the
     unheaded column a row keeps for its actions. */
  .narrow .table td:not(:first-child):has(form)::before,
  .narrow .table td[data-label=""]::before {
    content: none;
  }

  /* A field is its label beside its value, the labels in one column, so the
     eye runs down them; parts of a value stack beside the label. A value
     wraps anywhere, since a long address would otherwise push the block past
     its edge. :where keeps the rule weak enough for a title cell to undo. */
  .narrow .table td:where(:not(:first-child, :empty, [data-label=""], :has(form, > .cell-wrap:empty))) {
    display: grid;
    grid-template-columns: 7rem minmax(0, 1fr);
    column-gap: var(--space-8);
    align-items: baseline;
    justify-items: start;
    overflow-wrap: anywhere;
  }

  .narrow .table td:where(:not(:first-child, :empty, [data-label=""], :has(form, > .cell-wrap:empty))) > * {
    grid-column: 2;
  }

  /* On a touch screen a field's padding is what a 44px target adds to a
     line, and the field's link or list of days spans it. A field of text and
     a field of links then keep one pitch, and no target reaches past its
     field. */
  @media (width <= 48rem) {
    .narrow .table td:not(:first-child) {
      padding-block: calc((var(--touch) - 1lh) / 2);
    }

    .narrow .table td:not(:first-child) > a:only-child,
    .narrow .table td:not(:first-child) > .cell-wrap:only-child > a:only-child {
      margin-block: calc((1lh - var(--touch)) / 2);
    }

    .narrow .table td:not(:first-child) .attest-days:first-child {
      margin-top: calc((1lh - var(--touch)) / 2);
    }

    .narrow .table td:not(:first-child) .attest-days:last-child {
      margin-bottom: calc((1lh - var(--touch)) / 2);
    }
  }

  /* An avatar has no baseline, so its name and label centre on each other. */
  .narrow .table td:has(> .person-link)::before,
  .narrow .table td > .person-link {
    align-self: center;
  }

  .narrow .table td.num {
    text-align: start;
    font-variant-numeric: tabular-nums;
  }

  /* A long badge wraps, since the value column is narrower than its words. */
  .narrow .table td .badge {
    white-space: normal;
  }

  .narrow .table td[data-zero] {
    position: absolute;
    width: 1px;
    height: 1px;
    overflow: hidden;
    clip-path: inset(50%);
  }

  /* A field holds its targets whole, so none reaches a neighbouring field. */
  .narrow .table td > a:only-child,
  .narrow .table td > .cell-wrap:only-child > a:only-child {
    display: inline-flex;
    align-items: center;
    padding-block: 0;
    margin-block: 0;
  }

  .narrow .table td > form {
    margin-top: var(--space-8);
  }

  .narrow .table form:not(dialog *) .input {
    min-width: 0;
    width: 100%;
  }

  .narrow .table form:not(dialog *) .field {
    flex: 1 1 12rem;
  }
}

/* Close's rows lead with a checkbox, which would otherwise take the stacked
   block's title; it sits at the name's end instead. */
@container (width < 36rem) {
  .narrow .table tr:has(> td > .select-cell) {
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto;
  }

  .narrow .table tr:has(> td > .select-cell) > td:nth-child(n + 3) {
    grid-column: 1 / -1;
  }

  /* The box and the name share one line a touch target tall, set where a
     stacked block's title line sits, so the box stays beside the name when a
     note follows below. */
  .narrow .table td:first-child:has(> .select-cell) {
    grid-area: 1 / 2;
    display: flex;
    align-items: center;
    width: auto;
    min-height: calc(var(--touch) + var(--space-4));
    padding: var(--space-4) 0 0;
  }

  .narrow .table td:has(> .select-cell) + td {
    grid-area: 1 / 1;
    display: flex;
    align-items: center;
    min-height: calc(var(--touch) + var(--space-4));
    padding-block: var(--space-4) 0;
    font-size: 1rem;
    font-weight: 700;
    color: var(--heading);
  }

  .narrow .table td:has(> .select-cell) + td::before {
    content: none;
  }
}

/* A summary sits under its cell's other content, so its target takes its
   whole height there and reaches neither that content nor the next field. */
.table details > summary {
  padding-block: var(--space-10);
}

/* A dialog opened from a row sits in the row's markup, so the row's rules
   stop at it and it looks like every other dialog. */
.table form:not(dialog *) {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  gap: var(--space-8);
}

.table form:not(dialog *) .field {
  margin: 0;
  gap: var(--space-4);
}

.table form:not(dialog *) .field label {
  font-size: 0.75rem;
  color: var(--muted-foreground);
}

.table form:not(dialog *) .input {
  min-height: 40px;
  width: auto;
  min-width: 9rem;
}

/* A row's verbs, posting or opening a dialog, take one size, a step below
   the page's main action. */
/* A row's buttons keep one line, so the column is as wide as the pair and
   every row of a table stands as tall as its text. */
.table .actions:not(dialog *) {
  flex-wrap: nowrap;
  margin-top: 0;
  gap: var(--space-8);
}

.table .btn:not(dialog *) {
  min-height: 40px;
  padding: var(--space-8) var(--space-16);
  font-size: 1rem;
  white-space: nowrap;
}

/* A blocker's way to fix it takes its own line under the days, so no
   separator is left hanging where a narrow cell wraps. */
.blockers p > a:last-child {
  display: flex;
  align-items: center;
  width: fit-content;
  margin-top: var(--space-8);
}

.blockers .badge {
  margin-inline-end: var(--space-4);
}

/* Desk rows keep 40px controls for density; a finger needs the full target. */
@media (width <= 48rem) {
  .table form:not(dialog *) .input,
  .table .btn:not(dialog *) {
    min-height: var(--touch);
  }

  .attest-days li > a,
  .blockers a,
  .figures a,
  a.person-link,
  .table details > summary {
    min-height: var(--touch);
  }

  /* A count or a date gets the full target too. A stacked field gives it its
     whole height, so links on consecutive lines never overlap. */
  .table td > a:only-child,
  .table td > .cell-wrap:only-child > a:only-child {
    min-width: var(--touch);
    min-height: var(--touch);
  }

  /* A calendar's seven columns are under 44px wide at 320px, so a day fills
     its column and its height keeps the target large. */
  .cal .table td > .cal-day {
    min-width: 0;
  }

  .blockers a,
  .figures a {
    display: inline-flex;
    align-items: center;
    min-width: var(--touch);
  }

  /* The days' line is a target's height already, so the fix needs no gap. */
  .blockers p > a:last-child {
    margin-top: 0;
  }


  /* The label is hidden, so without this the hit area is the 24px box. */
  .select-cell .check label {
    width: var(--touch);
    height: var(--touch);
    inset: 50% auto auto 50%;
    translate: -50% -50%;
    clip-path: none;
    font-size: 0;
  }
}

/* A lone count is one or two digits wide; the link takes the cell's width so
   it is a target, not a speck. */
.table td.num > a {
  display: inline-block;
  padding-inline: var(--space-14);
  margin-inline: calc(-1 * var(--space-14));
}

/* A long label wraps inside its tab rather than push the tab to a second
   row, so every tab sits on the row its underline marks and none is hidden
   off-screen. */
.tabs {
  display: flex;
  gap: var(--space-4);
  border-bottom: 1px solid var(--border);
  margin-bottom: var(--space-24);
  overflow-x: auto;
  scrollbar-width: none;
}

.tabs a {
  display: inline-flex;
  align-items: center;
  min-height: var(--touch);
  flex: 0 1 auto;
  padding: 0 var(--space-16);
  color: var(--muted-foreground);
  font-weight: 500;
  text-align: center;
  text-decoration: none;
  border-bottom: 3px solid transparent;
  margin-bottom: -1px;
  transition: color 150ms ease-out, border-color 150ms ease-out;
}

.tabs a:hover {
  color: var(--foreground);
  border-bottom-color: var(--border-strong);
}

.tabs a[aria-current="page"] {
  color: var(--heading);
  font-weight: 700;
  border-bottom-color: var(--brand);
}

/* Chips: a filter that wraps, so every choice stays in view on a phone. */

.chips {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-8);
  margin-bottom: var(--space-20);
}

.chips a {
  display: inline-flex;
  align-items: center;
  min-height: var(--touch);
  padding: 0 var(--space-14);
  border: 1px solid var(--input);
  border-radius: var(--radius-sm);
  background: var(--card);
  color: var(--foreground);
  font-size: 0.9375rem;
  font-weight: 500;
  text-decoration: none;
  font-variant-numeric: tabular-nums;
  transition: border-color 150ms ease-out, background-color 150ms ease-out;
}

.chips a:hover {
  border-color: var(--link);
  color: var(--link);
}

.chips a[aria-current="page"] {
  background: var(--heading);
  border-color: var(--heading);
  color: var(--card);
  font-weight: 700;
}

/* Console sections. Below the desk width the home page lists them as its
   first block and every other page reaches them through its crumbs. */

.console-nav:not(.console-home) {
  display: none;
}

/* The gap between groups outweighs the space between a group's 44px rows,
   so each caption reads as the start of its group. */
.console-nav {
  display: grid;
  gap: var(--space-16);
  margin-bottom: var(--space-24);
  padding: var(--space-12) var(--space-8);
  background: var(--card);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  box-shadow: var(--shadow-sm);
}

.console-group > .caption {
  margin: var(--space-8) 0 var(--space-4) var(--space-12);
}

/* On the home page each group lays its links in columns that every group
   shares, so a long group fills the width rather than leaving a column
   half empty beside it. 13rem holds the longest label on one line. */
.console-home > .console-group {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(13rem, 1fr));
  column-gap: var(--space-24);
}

.console-home > .console-group > .caption {
  grid-column: 1 / -1;
}

.console-group > a {
  display: flex;
  align-items: center;
  gap: var(--space-10);
  min-height: var(--touch);
  padding: var(--space-6) var(--space-12);
  border-left: 3px solid transparent;
  border-radius: var(--radius-sm);
  color: var(--foreground);
  font-size: 0.9375rem;
  font-weight: 500;
  text-decoration: none;
  transition: background-color 150ms ease-out, color 150ms ease-out;
}

.console-group > a .icon {
  font-size: 1.25rem;
  color: var(--muted-foreground);
}

.console-group > a:hover {
  background: var(--selected);
  color: var(--heading);
}

.console-group > a[aria-current="page"] {
  background: var(--card);
  border-left-color: var(--brand);
  box-shadow: inset 0 0 0 1px var(--border);
  color: var(--selected-foreground);
  font-weight: 700;
}

.console-group > a[aria-current="page"] .icon {
  color: var(--selected-foreground);
}

/* Toasts and status: every state has an icon and words, never colour alone. */

.toast {
  display: flex;
  align-items: flex-start;
  gap: var(--space-12);
  padding: var(--space-12) var(--space-16);
  margin-bottom: var(--space-20);
  border-radius: var(--radius);
  border-left: 4px solid currentColor;
  font-weight: 500;
}

/* A save that worked needs no banner: a quiet line, its check still
   green. */
.toast-success {
  padding-inline: 0;
  border-left: 0;
  color: var(--muted-foreground);
  font-weight: 400;
}

.toast-success .icon {
  color: var(--success);
}

.toast-info {
  background: var(--info-surface);
  color: var(--info);
}

.toast-error {
  background: var(--danger-surface);
  color: var(--danger);
}

/* The icon marks where a message of several lines starts: centred on a
   1.5em line, a 1.25em icon sits 0.1 of its own em down. */
.toast > .icon {
  margin-top: 0.1em;
}

/* A long message wraps at the reading measure; its tint still spans the
   column. A word longer than the line breaks rather than scroll the page. */
.toast > :last-child {
  max-width: var(--measure);
  overflow-wrap: anywhere;
}

.toast a {
  color: inherit;
  font-weight: 700;
}

/* A button that does what a link would, such as opening a notification that
   is marked read on the way, reads as that link. */
.link {
  padding: 0;
  border: 0;
  background: none;
  color: var(--link);
  font: inherit;
  text-align: start;
  text-decoration: underline;
  text-underline-offset: 0.18em;
  text-decoration-thickness: 1px;
  cursor: pointer;
}

/* A button that reloads the page reads as the link beside it would. Its
   target overhangs the line instead of making the line taller. */
.toast .link {
  min-height: var(--touch);
  margin-block: calc((1lh - var(--touch)) / 2);
  color: inherit;
  font-weight: 700;
}

/* A hairline in the badge's own ink gives its tint an edge on a white card. */
/* The words set the badge's baseline, so a label beside it lines up with
   them and not with the icon. */
.badge {
  box-shadow: inset 0 0 0 1px color-mix(in srgb, currentColor 28%, transparent);
  display: inline-flex;
  align-items: baseline;
  gap: var(--space-4);
  padding: var(--space-2) var(--space-10) var(--space-2) var(--space-6);
  border-radius: 999px;
  font-size: 0.8125rem;
  font-weight: 500;
  white-space: nowrap;
}

.badge > .icon {
  align-self: center;
}

.badge-complete,
.badge-plan-approved {
  background: var(--success-surface);
  color: var(--success);
}

.badge-incomplete {
  background: var(--warning-surface);
  color: var(--warning);
  font-weight: 700;
}

.badge-open {
  background: var(--accent);
  color: var(--accent-foreground);
}

.badge-rest_day,
.badge-no_work,
.badge-plan-draft,
.badge-note {
  background: var(--neutral-surface);
  color: var(--muted-foreground);
}

.badge-inside {
  background: var(--success-surface);
  color: var(--success);
}

.badge-approaching,
.badge-plan-submitted,
.badge-plan-pending {
  background: var(--warning-surface);
  color: var(--warning);
}

.badge-over,
.badge-plan-rejected {
  background: var(--danger-surface);
  color: var(--danger);
  font-weight: 700;
}

.badge-cutover {
  background: var(--neutral-surface);
  color: var(--muted-foreground);
}

.badge-feedback-fixed {
  background: var(--success-surface);
  color: var(--success);
}

/* An idea Received is open, as a problem New is, so it is not green. */
.badge-feedback-received,
.badge-feedback-new,
.badge-feedback-in_progress {
  background: var(--info-surface);
  color: var(--info);
}

.badge-feedback-waiting {
  background: var(--warning-surface);
  color: var(--warning);
  font-weight: 700;
}

.badge-feedback-closed {
  background: var(--neutral-surface);
  color: var(--muted-foreground);
}

/* A feedback thread: the reporter's messages on the card surface, answers
   from super on the tinted one, so who said what reads at a glance. */
.thread {
  display: flex;
  flex-direction: column;
  gap: var(--space-12);
  max-width: var(--measure);
  margin: 0 0 var(--space-24);
  padding: 0;
  list-style: none;
}

.thread-message {
  padding: var(--space-14) var(--card-inset);
  background: var(--card);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
}

.thread-answer {
  background: var(--selected);
  border-color: color-mix(in srgb, var(--link) 25%, var(--border));
}

.thread-meta {
  margin: 0 0 var(--space-6);
  font-size: 0.875rem;
  color: var(--muted-foreground);
}

.thread-meta strong {
  color: var(--foreground);
}

.thread-body {
  margin: 0;
  white-space: pre-wrap;
  overflow-wrap: anywhere;
}

.thread-image {
  display: inline-block;
  margin-top: var(--space-12);
}

.thread-image img {
  display: block;
  max-width: min(100%, 24rem);
  height: auto;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
}

.thread-summary p {
  margin: 0 0 var(--space-12);
}

/* A person's day state takes one pair wherever it shows: under their name
   on Today, on Team today and the dashboard, on Month and Day, and in
   today's chip on a calendar. The icon and words carry the meaning. */
.badge-state-working,
.badge-state-done,
.cal-state-working,
.cal-state-done {
  --state-surface: var(--success-surface);
  --state-ink: var(--success);
}

.badge-state-on_break,
.cal-state-on_break {
  --state-surface: var(--accent);
  --state-ink: var(--accent-foreground);
}

.badge-state-teleworking,
.badge-state-external_work {
  --state-surface: var(--info-surface);
  --state-ink: var(--info);
}

.badge-state-on_leave {
  --state-surface: var(--leave-surface);
  --state-ink: var(--leave);
}

.badge-state-not_started,
.badge-state-absent,
.badge-state-not_working_day,
.cal-state-not_started {
  --state-surface: var(--neutral-surface);
  --state-ink: var(--muted-foreground);
}

/* Not started is ordinary until the person's morning reminder hour; only
   then does it ask for HR's eye. */
.badge-state-not_started.is-late {
  --state-surface: var(--warning-surface);
  --state-ink: var(--warning);
}

[class*="badge-state-"] {
  background: var(--state-surface);
  color: var(--state-ink);
}

.search-form {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  gap: var(--space-12);
  margin: var(--space-16) 0 var(--space-20);
}

.search-form .field {
  flex: 1 1 12rem;
  margin: 0;
}

.pick {
  margin: 0 0 var(--space-20);
}

.pick .field {
  margin: 0;
}

/* A picker is as wide as its longest name, so it does not stretch across a
   wide page, and never wider than the page. */
.pick .input {
  align-self: flex-start;
  width: auto;
  min-width: 12rem;
  max-width: 100%;
}

/* A line under a list filter: what it shows, then the links that change it.
   The gap parts them where a separator would end a wrapped line. */
.filter-note {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  column-gap: var(--space-16);
  margin: 0 0 var(--space-16);
  color: var(--muted-foreground);
}

.filter-note a {
  display: inline-flex;
  align-items: center;
  min-height: var(--touch);
}

/* In a toolbar the search sits at the row's end while the chips leave it
   room, and takes a row of its own, still one line, when they do not. */
.toolbar > .search-form {
  flex: 1 1 22rem;
  max-width: 28rem;
}

/* Chips, the search and a picker keep their own margins elsewhere; in a
   toolbar the one gap between them is the cluster's. The row lines its items
   up at their foot, so a field and the tabs keep no margin below. */
.toolbar > .chips,
.toolbar > .search-form,
.toolbar > .pick,
.toolbar > .figures,
.toolbar .field {
  margin: 0;
}

.toolbar > .tabs {
  margin-bottom: 0;
}

.toolbar > .figures {
  flex: 0 1 auto;
  grid-template-columns: repeat(2, minmax(8.5rem, 10.5rem));
}

/* Console forms: a role's line and its one button, the weekday tick grid,
   and the day a grant would override. */

.role-row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-8) var(--space-16);
  padding: var(--space-12) 0;
  border-top: 1px solid var(--border);
}

.role-row > p {
  flex: 1 1 12rem;
  margin: 0;
}

.role-row > .field-hint {
  flex-basis: 100%;
  order: 1;
}

/* A hint above the rows holds off their rule as the lead above it does. */
.card > .field-hint + .role-row {
  margin-top: var(--space-16);
}

/* The week is one row once its seven ticks fit, and four and three below
   that, so the weekend never splits off alone. The widest tick is 60px, so
   four still fit a 320px screen. */
.weekday-grid {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 0 var(--space-4);
}

.weekday-grid .check {
  gap: var(--space-8);
}

@container (width >= 28rem) {
  .weekday-grid {
    grid-template-columns: repeat(7, minmax(0, 1fr));
  }
}

.day-now {
  margin-bottom: var(--space-20);
  padding: var(--space-16) var(--space-20) var(--space-4);
  background: var(--muted);
  border-left: 4px solid var(--brand);
  border-radius: var(--radius);
}

.day-now h3 {
  margin-bottom: var(--space-8);
}

.day-now .stamps {
  margin: 0;
}

.day-now .stamps > div:last-child {
  border-bottom: 0;
}

/* Month close and archive: the select column's label is for screen
   readers, the person's name sitting in the next cell; 64 hex digits have no
   break, so a hash wraps anywhere. The column is as narrow as its head, and
   the box starts on its edge; the check hugs the box, so the touch area
   centred on it lands on the box. */

.table td:has(> .select-cell) {
  width: 1%;
}

.select-cell .check {
  position: relative;
  width: fit-content;
  min-height: 1.3125rem;
}

.select-cell .checkbox {
  width: 1.5rem;
  height: 1.5rem;
}

.hash {
  display: inline-block;
  max-width: 17ch;
  font-family: ui-monospace, "SFMono-Regular", Menlo, Consolas, monospace;
  font-size: 0.75rem;
  white-space: normal;
  word-break: break-all;
  vertical-align: top;
}

.archive-docs {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-8);
}

.hash-list {
  white-space: normal;
  margin: var(--space-8) 0 0;
  padding-left: var(--space-16);
  font-size: 0.75rem;
  color: var(--muted-foreground);
}

.hash-list li + li {
  margin-top: var(--space-6);
}

.hash-list .hash {
  display: block;
  max-width: none;
}

summary {
  cursor: pointer;
  padding-block: var(--space-12);
}

/* The stamping screen: Team today, headed by the signed-in person's card
   with its rail and the stamp due next, then the colleagues by place. */

.day-head {
  margin-bottom: var(--gap);
}

.day-head h1 {
  margin-bottom: var(--space-6);
}

/* The date or period a page shows steps back from its name in colour and
   size. On a phone it shrinks further and moves to the far end of the
   heading's row, and wraps there before the name does. */
.head-context {
  margin-left: 0.25em;
  color: var(--muted-foreground);
  font-size: 0.8em;
  font-weight: 600;
}

@media (width <= 48rem) {
  /* A name too long to share the row pushes the date onto a line of its
     own, still at the far end. */
  :is(.day-head, .page-head) h1:has(> .head-context) {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: 0 var(--space-16);
    white-space: nowrap;
  }

  /* Box centring leaves the date looking high beside the heading's larger
     lowercase, so it drops to centre on that. */
  .head-context {
    position: relative;
    top: 0.1em;
    margin-left: auto;
    font-size: 0.6em;
    white-space: normal;
    text-align: right;
  }
}

.head-facts {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-8) var(--space-12);
  margin: 0 0 var(--gap);
  color: var(--muted-foreground);
  font-weight: 500;
}

.day-head > .head-facts {
  margin-bottom: 0;
}

/* A link among the facts is a touch target, as a card link is. The padding
   reaches 44px and the negative margin gives it back, so the line is as
   tall with the link as without it. */
.head-facts a {
  padding-block: var(--space-10);
  margin-block: calc(var(--space-10) * -1);
}

.offline-note {
  display: none;
}

.offline-note.shown {
  display: flex;
}

.team {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-start;
  gap: var(--gap);
}

/* The gap alone spaces the heading, the card and the groups. */
.team > .day-head,
.team > .day-head h1 {
  margin-bottom: 0;
}

.team > :is(.day-head, .offline-note) {
  flex-basis: 100%;
}

/* The colleagues move beside the card as soon as a 13rem tile fits next to
   the card's content, whatever width that content takes. Alone on its row
   the card stretches to its cap; beside the colleagues their 1000:1 share
   of the free space keeps it at its content's width. */
.team > :not(.day-head, .offline-note, .day-card) {
  flex: 1000 1 13rem;
  min-width: 0;
}

.team .card {
  margin-bottom: 0;
}

.day-card {
  display: grid;
  padding: 0;
}

.day-card > * {
  min-width: 0;
  padding: var(--space-20) var(--space-24);
}

.day-lead {
  display: flex;
  flex-direction: column;
}

.day-figure {
  margin: 0;
  font-size: clamp(1.5rem, 1.2rem + 1vw, 2rem);
  text-wrap: balance;
}

.day-holiday,
.day-context {
  margin: var(--space-6) 0 0;
}

.day-context {
  color: var(--muted-foreground);
  font-weight: 500;
  font-variant-numeric: tabular-nums;
}

/* The button sits at the foot of the card. */
.day-lead > .day-action {
  margin-top: auto;
  padding-top: var(--space-20);
}

/* A refused press reads right under the button that made it, or at the foot
   of a day without stamps. */
.day-lead > .toast {
  margin: var(--space-12) 0 0;
}

.day-lead > .card-link {
  margin-bottom: 0;
}

/* On a day without stamps the mode form sits at the foot of the card. */
.day-side {
  display: flex;
  border-top: 1px solid var(--border);
  flex-direction: column;
  justify-content: flex-end;
  gap: var(--space-16);
}

.mode-head {
  margin: 0;
  font-weight: 600;
}

.mode-options {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-8);
  margin-top: var(--space-8);
}

.mode-options > .btn {
  padding: var(--space-4) var(--space-14);
  font-size: 0.875rem;
}

.mode-options > [aria-current="true"] {
  border-color: var(--link);
  color: var(--link);
}

/* The day rail: one stop per stamp, then the calculated end. A line joins
   each stop to the next, solid for the share of it time has covered (--fill,
   set by the page) and dashed for the rest; a green node is a stamp made,
   an orange ring the one due next. Capped so each time stays within reach of
   its label on a desk. */
.rail {
  --rail-input: 8.5rem;
  max-width: 34rem;
  margin: 0;
  padding: 0;
  list-style: none;
}

.rail-stop {
  position: relative;
  display: grid;
  grid-template-columns: 1.125rem minmax(0, 1fr);
  column-gap: var(--space-12);
  padding-bottom: var(--space-16);
}

.rail-stop:last-child {
  padding-bottom: 0;
}

.rail-stop.fill-1 {
  --fill: 0.1;
}

.rail-stop.fill-2 {
  --fill: 0.2;
}

.rail-stop.fill-3 {
  --fill: 0.3;
}

.rail-stop.fill-4 {
  --fill: 0.4;
}

.rail-stop.fill-5 {
  --fill: 0.5;
}

.rail-stop.fill-6 {
  --fill: 0.6;
}

.rail-stop.fill-7 {
  --fill: 0.7;
}

.rail-stop.fill-8 {
  --fill: 0.8;
}

.rail-stop.fill-9 {
  --fill: 0.9;
}

.rail-stop.fill-10 {
  --fill: 1;
}

/* The line runs from this node's centre to the next one's, under both
   nodes, so it meets them whatever the row's height. */
.rail-stop:not(:last-child)::before {
  content: "";
  position: absolute;
  top: var(--space-12);
  bottom: -0.75rem;
  left: calc(var(--space-8) - 1px);
  width: 2px;
  background:
    linear-gradient(var(--success), var(--success)) top / 100% calc(var(--fill, 0) * 100%) no-repeat,
    repeating-linear-gradient(var(--border-strong) 0 4px, transparent 4px 8px);
}

/* The dot sits on the label's baseline, so it follows the label down when
   an edit form beside it sets the line's baseline; 3px lower centres it on
   the label. */
.rail-node {
  position: relative;
  top: 3px;
  z-index: 1;
  align-self: baseline;
  width: 1rem;
  height: 1rem;
  border: 2px solid var(--heading);
  border-radius: 50%;
  background: var(--card);
}

.rail-stop.is-done .rail-node {
  border-color: var(--success);
  background: var(--success-surface);
}

.rail-stop.is-next .rail-node {
  border: 4px solid var(--brand);
}

.rail-stop.is-now .rail-node {
  border-color: var(--brand);
  background: var(--brand);
}

.rail-stop.is-end .rail-node {
  border-style: dashed;
}

.rail-what {
  display: flex;
  flex-direction: column;
  align-self: baseline;
  min-width: 0;
}

.rail-what small {
  color: var(--muted-foreground);
  font-size: 0.8125rem;
}

.rail-line {
  display: flex;
  align-items: center;
  gap: var(--space-8);
  min-height: 1.5rem;
}

/* A time with a next-day note under it keeps its first line on the label's. */
.rail-line > :is(.rail-label, .rail-time, form) {
  align-self: baseline;
}

/* The label keeps its line; a long time wraps instead. */
.rail-label {
  flex: none;
  font-weight: 600;
}

.rail-time {
  min-width: 0;
  margin-left: auto;
  color: var(--heading);
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  text-align: right;
}

.rail-time small {
  display: block;
  font-weight: 400;
}

.rail-time.is-soft {
  color: var(--muted-foreground);
  font-weight: 400;
}

.rail-now {
  color: var(--accent-foreground);
}

/* A 44px target that takes no more room in the line than its icon. */
.rail-fix {
  display: grid;
  flex: none;
  place-items: center;
  width: var(--touch);
  height: var(--touch);
  margin: -10px -12px -10px 0;
  border-radius: var(--radius);
  color: var(--link);
  text-decoration: none;
}

/* The pencil swaps the time for this form; without script the form stays
   hidden and the pencil is a link. */
.rail-line > form {
  display: none;
}

.rail-line.is-editing {
  flex-wrap: wrap;
}

.rail-line.is-editing > :is(.rail-time, .rail-fix) {
  display: none;
}

/* Beside a long label on a phone the form drops to a line of its own. The
   form draws the field's box so the buttons sit inside it, after the time,
   and its right edge meets the pencils' bordered icons. */
.rail-line.is-editing > form {
  display: flex;
  align-items: center;
  margin: var(--space-4) -4px 0 auto;
  padding-right: var(--space-4);
  background: var(--card);
  border: 1px solid var(--input);
  border-radius: var(--radius);
}

.rail-line.is-editing > form:hover {
  border-color: var(--foreground);
}

.rail-line.is-editing > form:has(.input:focus-visible) {
  outline: 3px solid var(--ring);
  outline-offset: 2px;
}

/* An inset shadow thickens the invalid border without growing the box. */
.rail-line.is-editing > form:has([aria-invalid="true"]) {
  border-color: var(--destructive);
  box-shadow: inset 0 0 0 1px var(--destructive);
}

.rail-line.is-editing > form > .btn {
  margin: -1px -4px;
  color: var(--muted-foreground);
}

.rail-what > .field-error {
  margin: var(--space-6) 0 0;
}

.rail-line > form .input {
  width: var(--rail-input);
  min-height: 42px;
  background: none;
  border: 0;
  outline: 0;
}

/* Drawn as the confirm buttons are: the 44px target stays, and hover and
   focus mark only the icon's box. */
a.rail-fix .icon {
  padding: var(--space-4);
  border: 1px solid color-mix(in srgb, var(--border) 50%, transparent);
  border-radius: var(--radius-sm);
  font-size: 1.125rem;
}

a.rail-fix:hover .icon {
  background: var(--muted);
}

a.rail-fix:focus-visible {
  outline: 0;
}

a.rail-fix:focus-visible .icon {
  outline: 2px solid var(--ring);
}

@container page (width >= 52rem) {
  .day-card:has(> .day-side) {
    grid-template-columns: minmax(0, 5fr) minmax(0, 6fr);
  }

  .day-side {
    border-top: 0;
    border-left: 1px solid var(--border);
  }
}

@media (width <= 48rem) {
  .day-card > * {
    padding: var(--space-16);
  }
}

.stamps {
  display: grid;
  margin: 0 0 var(--space-20);
}

.stamps > div {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: var(--space-16);
  padding: var(--space-10) 0;
  border-bottom: 1px solid var(--border);
}

.stamps > div:first-child {
  padding-top: 0;
}

.stamps dt {
  color: var(--muted-foreground);
}

.stamps dd {
  margin: 0;
  font-size: 1.125rem;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  text-align: right;
}

.figures {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--space-12);
  margin: 0 0 var(--space-20);
}

/* Tiles stop growing at 10.5rem, so a wide card shows a row of figures rather
   than four stretched slabs. auto-fit counts its columns at that maximum, so
   three fit the 590px a person's record leaves its tiles beside the team
   list, and five fit the leave balance at 1024px. */
@container (width >= 30rem) {
  .figures {
    grid-template-columns: repeat(auto-fit, minmax(8.5rem, 10.5rem));
  }
}

/* The number reads first, and every tile's number sits on the same line
   whether or not its label wraps. */
.figures > div {
  display: flex;
  flex-direction: column-reverse;
  justify-content: flex-end;
  gap: var(--space-2);
  padding: var(--space-12) var(--space-14);
  background: var(--tile);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  min-width: 0;
}

.figures dt {
  font-size: 0.8125rem;
  font-weight: 500;
  color: var(--muted-foreground);
}

.figures dd {
  margin: 0;
  font-size: 1.5rem;
  font-weight: 700;
  line-height: 1.1;
  font-variant-numeric: tabular-nums;
  color: var(--heading);
}

.figures dd > a {
  display: inline-flex;
  align-items: center;
  min-height: var(--touch);
  margin-block: -0.5rem;
}

/* The buttons are drawn on the card's surface, as everywhere else, rather
   than on the warning tint. */
.stamp-confirm :where(.btn) {
  background: var(--card);
}

.stamp-confirm {
  padding: var(--space-16);
  border-radius: var(--radius);
  background: var(--warning-surface);
  color: var(--warning);
}

.stamp-confirm p {
  margin: 0 0 var(--space-12);
}

/* Not now takes the stamp button's box, so it covers the spot the press
   came from, at the secondary's size and weight. */
.stamp-confirm .btn-secondary {
  font-size: 1rem;
  font-weight: 500;
}

/* Not now and the confirmation share a row while both labels fit on one
   line; once either would wrap, each takes a row of its own. */
.stamp-confirm .actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-12);
}

.stamp-confirm .actions > * {
  flex: 1 1 auto;
}

.stamp-confirm .btn-stamp {
  width: 100%;
}

.btn-stamp {
  width: 100%;
  min-height: 56px;
  font-size: 1.25rem;
  font-weight: 700;
}

.btn-stamp .icon {
  font-size: 1.5rem;
}

.card-link {
  margin: var(--space-20) 0;
}

.card-link a {
  display: inline-flex;
  align-items: center;
  gap: var(--space-6);
  min-height: var(--touch);
  font-weight: 500;
}

/* One rule runs under the icon and the words: text-decoration skips the
   icon and the gap after it. The rule is drawn, since a border would sit at
   the foot of the 44px target. */
.card-link a:has(> .icon) {
  text-decoration: none;
  background: linear-gradient(currentColor, currentColor) left calc(50% + 0.75em) / 100% 1px no-repeat;
}

/* A quiet line above the heading. The chevron is inline, not inline-block,
   so one underline runs under it and the words. Its glyph starts a third of
   an em into its box: the negative margin puts the visible chevron on the
   heading's edge, and the clip trims the underline left of it until a link
   takes focus and its ring needs the room. */
.crumbs {
  margin-top: var(--space-8);
  clip-path: inset(-1rem -100vw -1rem 0);
}

.crumbs:has(:focus-visible) {
  clip-path: none;
}

.crumbs ol {
  list-style: none;
  margin: 0 0 var(--space-12);
  padding: 0;
  font-size: 0.875rem;
  line-height: 1.5;
  color: var(--muted-foreground);
}

.crumbs li {
  display: inline;
}

.crumbs li + li::before {
  content: "\203A" / "";
  margin: 0 0.45em;
}

.crumbs a {
  color: var(--link);
  text-decoration: underline;
  text-decoration-thickness: 1px;
  text-underline-offset: 0.22em;
  padding-block: 0.35rem;
}

.crumbs a:hover {
  text-decoration-thickness: 2px;
}

.crumbs .icon {
  display: inline;
  vertical-align: -0.24em;
  margin: 0 -0.15em 0 -0.3333em;
}

.cutover-note {
  margin-bottom: var(--space-20);
}

/* The arrows carry no words: the period's name is in the heading beside
   them. */
.pager {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-8);
}

.pager-steps {
  display: flex;
  align-items: center;
  gap: var(--space-8);
  min-width: 0;
}

.pager .btn-icon {
  width: var(--touch);
}

/* The edge of the record: the arrow holds its place so the controls do not
   shift between periods. */
.pager span.btn-icon {
  opacity: 0.4;
  cursor: default;
}

.period-pick {
  display: flex;
  gap: var(--space-8);
  min-width: 0;
}

/* The select posts through the form via writes around it, which takes no
   box of its own, so the select sizes as the row's item. */
.period-pick > form {
  display: contents;
}

.period-pick .input {
  flex: 0 1 12rem;
  width: auto;
  min-width: 0;
}

/* A tablet keeps the heading and its pager on one row; below this they no
   longer fit beside each other. */
@media (width < 40rem) {
  .page-head {
    flex-direction: column;
    align-items: stretch;
  }

  /* Under the period it changes, which sits at the heading's far end. */
  .page-head > .pager,
  .page-head .pager-steps {
    justify-content: flex-end;
  }

  /* The period's select takes the width between the arrows, never narrower
     than its longest option. */
  .page-head .pager-steps,
  .page-head .period-pick {
    flex: 1 0 auto;
  }

  .page-head .period-pick .input {
    flex: 1;
  }

  /* The heading's row holds the way back, since the select under it names
     the period. A way back too long to share the row drops under the heading
     whole rather than wrap its label. */
  .page-head:has(.period-pick) {
    flex-direction: row;
    flex-wrap: wrap;
    align-items: center;
    column-gap: var(--space-16);
  }

  .page-head:has(.period-pick) > .pager {
    display: contents;
  }

  .page-head:has(.period-pick) .pager-back {
    margin-left: auto;
    white-space: nowrap;
  }

  .page-head:has(.period-pick) .pager-steps {
    flex: 1 0 100%;
  }
}

/* The period's select names the period beside the heading, so the heading
   leaves the name to a screen reader rather than show it twice. */
.page-head:has(.period-pick) .head-context {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

.day-times {
  font-size: 0.875rem;
  color: var(--muted-foreground);
}

.day-times .seg {
  white-space: nowrap;
}

.gap {
  color: var(--warning);
  font-weight: 700;
}

.time-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(8rem, 1fr));
  gap: 0 var(--space-16);
}

/* Mode names ("O meu dia habitual") need a wider select than a time does,
   and a date field needs 172px to show its whole date beside the picker's
   icon, so a pair of dates stacks on a phone rather than clip. */
.time-grid:has(select, input[type="date"]) {
  grid-template-columns: repeat(auto-fit, minmax(11rem, 1fr));
}

.changes {
  list-style: none;
  padding: 0;
  margin: 0;
}

.changes > li {
  padding: var(--space-12) 0;
  border-bottom: 1px solid var(--border);
}

.changes > li:first-child {
  padding-top: 0;
}

.changes > li:last-child {
  border-bottom: 0;
  padding-bottom: 0;
}

.request-line {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-4) var(--space-8);
}

.changes p {
  margin: 0 0 var(--space-4);
}

.changes form:not(:first-child) {
  margin-top: var(--space-8);
}

/* A notification opens from anywhere along its row. The row's padding takes
   the tap too, so a one-line one is a touch target tall without spacing its
   row apart from the others. */
.changes .link {
  position: relative;
  display: block;
  width: 100%;
}

.changes .link::after {
  content: "";
  position: absolute;
  inset: calc((1lh - var(--touch)) / 2) 0;
}

.changes .link .badge {
  margin-inline-end: var(--space-8);
}

/* No component lists lines under a row: only a digest's notification has
   any, the corrections its count sums up. */
.notification-lines {
  margin: var(--space-4) 0;
  padding-left: var(--space-20);
  list-style: disc;
}

/* Telework attestation: the days waiting, and the flag on a day that is. */

.attest-fieldset {
  min-width: 0;
  margin: 0 0 var(--space-16);
  padding: 0;
  border: 0;
}

.attest-days {
  list-style: none;
  padding: 0;
  margin: 0 0 var(--space-16);
}

.attest-days li {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  align-items: center;
  gap: 0 var(--space-12);
  padding: var(--space-8) 0;
  border-bottom: 1px solid var(--border);
}

.attest-days li:last-child {
  border-bottom: 0;
}

/* In a table the list's first and last days line up with the row's other
   cells. */
.table .attest-days li {
  padding-block: var(--space-4);
}

.table .attest-days li:first-child {
  padding-top: 0;
}

.table .attest-days li:last-child {
  padding-bottom: 0;
}

.attest-days li > a {
  display: inline-flex;
  align-items: center;
}

.attest-days time {
  white-space: nowrap;
}

.table .attest-days {
  margin: 0;
  width: fit-content;
}

/* A day's target fills its line, so the targets of consecutive days meet
   without overlapping. A row's first list overhangs by the difference, so its
   first date stays level with the row's other cells. */
@media (width <= 48rem) {
  .table .attest-days li {
    padding-block: 0;
  }

  .table .attest-days:first-child {
    margin-top: -0.625rem;
  }
}

/* A day's flag drops under its date when the cell is too narrow for both. */
.table .attest-days li {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
}

.attest-flag {
  display: inline-flex;
  align-items: center;
  gap: var(--space-4);
  margin-left: var(--space-8);
  font-size: 0.8125rem;
  font-weight: 500;
  color: var(--info);
}

p.attest-flag {
  margin-left: 0;
}

/* The plan calendar: a fixed seven-column table whose cells carry the day's
   state as a coloured chip with icon and words. td:empty is a day outside
   the month. */

.cal .table {
  table-layout: fixed;
}

.cal .table th,
.cal .table td {
  padding: 0;
  white-space: normal;
  border-left: 1px solid var(--border);
}

.cal .table th:first-child,
.cal .table td:first-child {
  border-left: 0;
}

.cal .table thead th {
  position: static;
  text-align: center;
  padding: var(--space-8) var(--space-4);
}

.cal .table tbody tr:hover {
  background: transparent;
}

.cal .table td:empty {
  background: repeating-linear-gradient(-45deg, transparent 0 6px, color-mix(in srgb, var(--muted) 60%, transparent) 6px 7px);
}

.cal-day {
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
  min-height: 5.25rem;
  padding: var(--space-8);
}

/* An inert day's number lines up with a button day's, which sits inside
   the cell's 4px padding and the button's 1px border. */
div.cal-day {
  padding: calc(var(--space-8) + 5px);
}

/* A future working day is a button that fills the request form. Its
   border is what marks it as a control, so it takes the input border
   (4.6:1) rather than --border-strong (1.9:1). */
.cal .table td:has(> button.cal-day) {
  padding: 4px;
}

button.cal-day {
  position: relative;
  width: 100%;
  height: 100%;
  min-height: calc(5.25rem - 8px);
  margin: 0;
  border: 1px solid var(--input);
  border-radius: var(--radius-sm);
  font: inherit;
  text-align: left;
  color: inherit;
  background: var(--card);
  cursor: pointer;
}

/* The cell's padding takes the tap too, so the target is the whole cell. */
button.cal-day::after {
  content: "";
  position: absolute;
  inset: -4px;
}

button.cal-day:hover {
  border-color: var(--link);
  background: color-mix(in srgb, var(--accent) 50%, var(--card));
}

button.cal-day:focus-visible {
  outline: 3px solid var(--ring);
  outline-offset: 1px;
}

/* The day the form holds looks like the day on show in a day page's pane. */
button.cal-day[aria-pressed="true"] {
  background: var(--selected);
  box-shadow: inset 0 -3px 0 var(--brand);
  color: var(--selected-foreground);
}

.cal-num {
  align-self: flex-start;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 1.75rem;
  height: 1.75rem;
  padding: 0 var(--space-6);
  border-radius: 999px;
  font-weight: 700;
  font-size: 0.9375rem;
}

.cal-day[aria-current="date"] .cal-num {
  background: var(--brand);
  color: var(--navy-deep);
}

.cal-day[aria-current="date"] {
  box-shadow: inset 0 0 0 2px var(--brand);
}

.cal-state {
  display: inline-flex;
  align-items: center;
  gap: var(--space-4);
  padding: var(--space-2) var(--space-8) var(--space-2) var(--space-6);
  border-radius: var(--radius-sm);
  font-size: 0.75rem;
  font-weight: 500;
  line-height: 1.3;
  background: var(--state-surface, var(--neutral-surface));
  color: var(--state-ink, var(--muted-foreground));
}

.cal-state .icon {
  font-size: 1rem;
}

.cal-legend {
  display: flex;
  list-style: none;
  flex-wrap: wrap;
  gap: var(--space-6) var(--space-16);
  margin: -0.5rem 0 var(--space-20);
  padding: 0;
  font-size: 0.8125rem;
}

/* The pull-up tucks the legend under the Plan calendar; after a line of
   text, as on the leave map, it keeps its distance. */
.field-hint + .cal-legend {
  margin-top: var(--space-12);
}

.cal-legend li {
  display: inline-flex;
  align-items: center;
  gap: var(--space-4);
  color: var(--state-ink, var(--muted-foreground));
}

.cal-weekly_rest {
  --state-surface: var(--neutral-surface);
  --state-ink: var(--muted-foreground);
}

.cal-day.cal-weekly_rest {
  background: color-mix(in srgb, var(--muted) 45%, transparent);
}

.cal-public_holiday {
  --state-surface: var(--info-surface);
  --state-ink: var(--info);
}

.cal-annual_leave {
  --state-surface: var(--leave-surface);
  --state-ink: var(--leave);
}

.cal-justified_absence,
.cal-unjustified_absence {
  --state-surface: var(--neutral-surface);
  --state-ink: var(--foreground);
}

.cal-pending {
  --state-surface: var(--warning-surface);
  --state-ink: var(--warning);
}

.cal-approved {
  --state-surface: var(--success-surface);
  --state-ink: var(--success);
}

.cal-rejected {
  --state-surface: var(--danger-surface);
  --state-ink: var(--danger);
}

.cal-incomplete {
  --state-surface: var(--warning-surface);
  --state-ink: var(--warning);
}

.cal-day.cal-rejected .cal-state {
  text-decoration: line-through;
}

/* The month: every day is its page's link and fills its cell, so the whole
   cell is the target and the hover covers it. */
.month-cal .table td:has(> .cal-day) {
  height: 1px;
}

/* The table's rule for a lone link in a cell (inline-block, negative
   margins) is for text links; a day cell is a block. */
.month-cal .table td > a.cal-day {
  display: flex;
  height: 100%;
  margin: 0;
  color: inherit;
  text-decoration: none;
  font-variant-numeric: tabular-nums;
}

.month-cal a.cal-day:hover {
  background: var(--row-hover);
  color: inherit;
}

/* The day on show, in the day page's pane, takes the list pane's selected
   fill and a bar under it; a ring would read as today's. */
.month-cal a.cal-day[aria-current="page"] {
  background: var(--selected);
  box-shadow: inset 0 -3px 0 var(--brand);
  color: var(--selected-foreground);
  font-weight: 700;
}

.month-cal a.cal-day:focus-visible {
  outline: 3px solid var(--ring);
  outline-offset: -3px;
}

.month-cal .cal-off {
  background: color-mix(in srgb, var(--muted) 45%, transparent);
}

.month-cal .cal-attention {
  background: var(--warning-surface);
}

.cal-future .cal-num {
  color: var(--muted-foreground);
  font-weight: 500;
}

.cal-hours {
  font-weight: 700;
  font-size: 0.875rem;
}

/* A day worked away from the usual mode is the one outlined chip: its shape
   differs from every filled state, so it is found without the colour. */
.cal-away {
  --state-surface: transparent;
  --state-ink: var(--heading);
}

.cal-state.cal-away {
  box-shadow: inset 0 0 0 1px currentColor;
  font-weight: 600;
}

.cal-attest {
  --state-surface: var(--info-surface);
  --state-ink: var(--info);
}

.month-cal .cal-state > span:not(.icon) {
  overflow-wrap: normal;
  hyphens: none;
}

/* The calendar's own width decides whether the chips carry words: under
   48rem a cell is too narrow for "Teletrabalho", so the chips keep their
   icons and the legend under the calendar names them. */
@container (width >= 48rem) {
  .month-cal .table td > .cal-day {
    min-height: 5.25rem;
    padding: var(--space-8);
    align-items: stretch;
  }

  .month-cal .cal-num {
    align-self: flex-start;
    min-width: 1.75rem;
    height: 1.75rem;
    font-size: 0.9375rem;
  }

  .month-cal .cal-state {
    padding: var(--space-2) var(--space-8) var(--space-2) var(--space-6);
    background: var(--state-surface, var(--neutral-surface));
  }

  .month-cal .cal-state > span:not(.icon) {
    position: static;
    width: auto;
    height: auto;
    overflow: visible;
    clip-path: none;
    white-space: normal;
  }

  .month-cal .cal-state .icon {
    font-size: 1rem;
  }
}

@container (width < 48rem) {
  .month-cal .table td > .cal-day {
    min-height: 3.25rem;
    padding: var(--space-4) var(--space-2);
    align-items: center;
    gap: var(--space-2);
  }

  .month-cal .cal-num {
    align-self: center;
    min-width: 1.5rem;
    height: 1.5rem;
    font-size: 0.875rem;
  }

  .month-cal .cal-state {
    padding: var(--space-2);
    background: transparent;
  }

  .month-cal .cal-state.cal-away {
    padding: 0;
    border-radius: 4px;
  }

  .month-cal .cal-state > span:not(.icon) {
    position: absolute;
    width: 1px;
    height: 1px;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
  }

  .month-cal .cal-state .icon {
    font-size: 1.125rem;
  }

  .month-cal .cal-hours {
    font-size: 0.75rem;
  }
}

/* The legend and the month's export share the row under the calendar; on a
   phone the export wraps under the legend, still at the right edge. */
.cal-foot {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-12) var(--space-16);
  margin: -0.5rem 0 var(--space-20);
}

.cal-foot > .cal-legend {
  flex: 1 1 auto;
  margin: 0;
}

.cal-export {
  display: inline-flex;
  align-items: center;
  gap: var(--space-6);
  height: 28px;
  margin-left: auto;
  padding: 0 var(--space-10);
  font-size: 0.8125rem;
  font-weight: 500;
  white-space: nowrap;
  color: var(--foreground);
  text-decoration: none;
  background: var(--card);
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-sm);
}

.cal-export:hover {
  background: var(--row-hover);
  color: var(--foreground);
}

.cal-export .icon {
  font-size: 1rem;
}

/* The leave plan: twelve month grids, a tile per working day whose
   checkbox covers the tile. Weekends and holidays are inert cells. */

.leave-year {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(min(20rem, 100%), 1fr));
  gap: var(--space-16);
  margin: var(--space-16) 0 var(--space-24);
}

/* A month already over opens on its own, so it keeps its folded height
   beside one that is open. */
.leave-year:has(> .leave-past) {
  align-items: start;
}

.leave-month {
  margin: 0;
  padding: var(--space-14);
  border: 1px solid var(--border);
  border-radius: var(--radius);
}

.leave-past summary {
  cursor: pointer;
  font-family: var(--font-heading);
  font-weight: 600;
  color: var(--heading);
}

.leave-past[open] summary {
  margin-bottom: var(--space-10);
}

.leave-month legend {
  float: left;
  width: 100%;
  margin-bottom: var(--space-10);
  font-family: var(--font-heading);
  font-weight: 600;
  color: var(--heading);
}

.leave-grid {
  clear: both;
  display: grid;
  grid-template-columns: repeat(7, minmax(0, 1fr));
  gap: 3px;
}

/* Drawn as the calendars' column heads, at a size the year's grid fits. */
.leave-wd {
  font-size: 0.6875rem;
  font-weight: 600;
  text-align: center;
  color: var(--muted-foreground);
  padding-bottom: var(--space-2);
}

.leave-off,
.leave-blank,
.leave-grid .check {
  aspect-ratio: 1;
  min-height: 0;
  display: grid;
  place-items: center;
  border-radius: var(--radius-sm);
  font-size: 0.875rem;
  font-variant-numeric: tabular-nums;
}

.leave-off {
  color: var(--muted-foreground);
  background: color-mix(in srgb, var(--muted) 55%, transparent);
}

.leave-holiday {
  --state-ink: var(--info);
  position: relative;
  color: var(--info);
  background: var(--info-surface);
}

/* Each cell state carries the glyph its legend entry shows, so a holiday, a
   day already reached and a planned day differ by more than their tint. */
.leave-holiday::after,
.leave-grid .check:has(:checked) label::after,
.leave-grid .check:has(:disabled:not(:checked)) label::after {
  font-family: "Material Symbols Outlined";
  font-size: 0.6875rem;
  line-height: 1;
  position: absolute;
  top: 2px;
  right: 2px;
}

.leave-holiday::after {
  content: "flag";
}

.leave-grid .check:has(:disabled:not(:checked)) label::after {
  content: "history";
}

.leave-grid .check {
  position: relative;
  gap: 0;
  border: 1px solid var(--border-strong);
  background: var(--card);
  font-weight: 500;
  transition: background-color 120ms ease-out, border-color 120ms ease-out;
}

/* The box covers the tile's border too, so the whole tile takes the tap. */
.leave-grid .checkbox {
  position: absolute;
  inset: -1px;
  width: calc(100% + 2px);
  height: calc(100% + 2px);
  margin: 0;
  opacity: 0;
  cursor: pointer;
}

.leave-grid .check label {
  pointer-events: none;
}

.leave-grid .check:hover {
  border-color: var(--link);
}

.leave-grid .check:has(:focus-visible) {
  outline: 3px solid var(--ring);
  outline-offset: 1px;
}

.leave-grid .check:has(:checked) {
  background: var(--leave-surface);
  border-color: var(--leave);
  color: var(--leave);
  font-weight: 700;
}

.leave-grid .check:has(:checked) label::after {
  content: "check_circle";
}

.leave-grid .check:has(:disabled) {
  border-style: dashed;
  border-color: var(--border);
  color: var(--muted-foreground);
  background: color-mix(in srgb, var(--muted) 35%, transparent);
}

.leave-grid .check:has(:disabled) .checkbox {
  cursor: default;
}

.leave-grid .check:has(:checked:disabled) {
  border-style: solid;
  background: color-mix(in srgb, var(--leave-surface) 60%, transparent);
  color: var(--leave);
}

/* Below two 20rem months and their gap the months stack, and one alone in
   a phone's card is too narrow for seven 44px columns. A month ahead then
   drops its box, its grid spans most of the card's padding with a 2px gap,
   and the weekday names shrink so a weekend column fits its own. */
@container (width < 41rem) {
  fieldset.leave-month {
    padding: 0;
    border: 0;
  }

  fieldset.leave-month .leave-grid {
    margin-inline: calc(-1 * var(--space-12));
    gap: 2px;
  }

  .leave-wd {
    font-size: 0.625rem;
  }
}

/* Phone and tablet held upright: the app nav moves to a fixed bar at the
   bottom, in reach of a thumb, and sign-out shrinks to its icon, keeping its
   name in aria-label. */

@media (width <= 48rem) {
  :root {
    --nav-height: calc(3.75rem + env(safe-area-inset-bottom));
  }

  /* The room is for the tab bar, which a standalone page does not have. */
  body:not(:has(.standalone)) {
    padding-bottom: var(--nav-height);
  }

  html {
    scroll-padding-bottom: calc(var(--nav-height) + 0.5rem);
  }

  .download-toast {
    bottom: calc(var(--nav-height) + var(--space-12));
  }

  html:has(.leave-actionbar) {
    scroll-padding-bottom: calc(var(--nav-height) + var(--actionbar-height) + 0.5rem);
  }

  /* On a phone the year's months run to many screens, so the leave plan's
     actions stay in reach just above the fixed app nav. */
  .leave-actionbar {
    position: sticky;
    bottom: var(--nav-height);
    z-index: 2;
    margin: var(--space-16) calc(-1 * var(--card-inset)) 0;
    padding: var(--space-12) var(--card-inset);
    background: var(--card);
    border-top: 1px solid var(--border);
  }

  /* A crumb takes a 44px tap around its text by reaching into the trail's
     margins, so the heading below keeps its place. */
  .crumbs a {
    position: relative;
  }

  .crumbs a::after {
    content: "";
    position: absolute;
    inset: calc((100% - var(--touch)) / 2) min(0px, calc(100% - var(--touch))) calc((100% - var(--touch)) / 2) 0;
  }

  .cal-export {
    height: auto;
    min-height: var(--touch);
  }

  .shell-header {
    flex-wrap: nowrap;
    --header-gap: 0.75rem;
    justify-content: space-between;
    gap: var(--header-gap);
    min-height: 3.5rem;
    padding-block: var(--space-6);
  }

  /* The bell sits too near the right edge to hang a panel from it, so the
     panel spans the header's width instead. Both panels hang from the
     header's edge, so they open at one height. */
  .bell,
  .account-menu {
    position: static;
  }

  .bell-panel {
    left: var(--gutter);
    right: var(--gutter);
    width: auto;
  }

  .account-panel {
    right: var(--gutter);
  }

  /* With the links in the tab bar the name has the header's room, and a long
     one gives way to the brand. */
  .account-menu {
    min-width: 0;
  }

  .brand img {
    height: 30px;
  }

  .brand-name {
    font-size: 1.8125rem;
  }

  .shell-nav {
    position: fixed;
    left: 0;
    right: 0;
    bottom: 0;
    z-index: 5;
    flex: none;
    flex-wrap: nowrap;
    justify-content: space-around;
    gap: 0;
    height: var(--nav-height);
    padding: var(--space-4) var(--space-4) env(safe-area-inset-bottom);
    background: var(--chrome);
    border-top: 1px solid var(--chrome-line);
    box-shadow: 0 -2px 8px rgb(10 25 47 / 0.25);
    overflow-x: auto;
    scrollbar-width: none;
  }

  /* Each link is as wide as its label and never narrower than a touch
     target, so six Portuguese labels fit 320px where six equal columns
     would clip the longest. */
  .shell-nav a {
    flex: 1 1 auto;
    min-width: var(--touch);
    flex-direction: column;
    justify-content: center;
    gap: var(--space-2);
    min-height: 3.25rem;
    padding: 0 var(--space-2);
    font-size: 0.75rem;
    letter-spacing: 0;
    text-transform: none;
    font-weight: 500;
    white-space: nowrap;
  }

  .shell-nav a .icon {
    font-size: 1.5rem;
    opacity: 1;
  }

  .shell-nav a {
    position: relative;
  }

  .shell-nav a[aria-current="page"] {
    font-weight: 700;
  }

  /* The phone bar marks the current tab the way the desk header does, at
     its top edge. */
  .shell-nav a[aria-current="page"]::before {
    content: "";
    position: absolute;
    top: 0;
    left: 25%;
    right: 25%;
    height: 3px;
    border-radius: 0 0 3px 3px;
    background: var(--brand);
  }

  .shell-header .btn-signout {
    min-width: var(--touch);
    min-height: var(--touch);
    padding: var(--space-8);
  }

  .btn-signout .btn-label {
    display: none;
  }

  main {
    padding-bottom: var(--space-32);
  }

  :root {
    --card-inset: var(--space-16);
  }

  .card {
    padding-block: var(--space-20);
  }

  .lead {
    font-size: 1rem;
  }

  .day-times {
    font-size: 0.8125rem;
  }

  .figures {
    gap: var(--space-8);
  }

  .figures dd {
    font-size: 1.25rem;
  }

  .cal-day {
    min-height: 3.25rem;
    padding: var(--space-4);
    align-items: center;
  }

  .cal-num {
    align-self: center;
    min-width: 1.5rem;
    height: 1.5rem;
    font-size: 0.875rem;
  }

  /* A phone's day cell keeps only the state's icon and leaves its words to
     a screen reader; a list beside the calendar keeps them in view. */
  .cal-day .cal-state {
    padding: var(--space-2);
    background: transparent;
  }

  .cal-day .cal-state > span:not(.icon) {
    position: absolute;
    width: 1px;
    height: 1px;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
  }

  .cal-day .cal-state .icon {
    font-size: 1.125rem;
  }

  /* A day to tick is 44px square, and a column with no working day, a
     weekend for most people, narrows to its weekday's name to make room. A
     month already over holds no target, so its cells narrow with the
     columns and keep the row's height. */
  .leave-grid {
    grid-template-columns: repeat(7, minmax(min-content, 1fr));
  }

  .leave-off,
  .leave-blank,
  .leave-past .check {
    aspect-ratio: auto;
  }

  .leave-off,
  .leave-blank,
  .leave-grid .check {
    min-height: var(--touch);
  }

  .table-title {
    padding: var(--space-20) var(--card-inset) var(--space-8);
  }

  /* Three labels fit one row at 360px in either language. */
  .tabs a {
    padding-inline: var(--space-12);
  }

  .chips {
    gap: var(--space-6);
  }

  .chips a {
    min-height: var(--touch);
    padding: 0 var(--space-12);
    font-size: 0.875rem;
  }
}

/* On a phone the bar slides away while a field has focus, so the keyboard
   never leaves a strip of navigation over the field being typed in. */
@media (width <= 48rem) {
  .shell:has(.input:focus, textarea:focus) .shell-nav {
    translate: 0 100%;
    transition: translate 150ms ease-out;
  }

}

/* The links never wrap. Between the bar and the desk the header holds them
   on one line only when they are set tighter and sign-out keeps its icon
   alone. Super's six need that up to 72rem, and below 60rem they drop
   their icons too. */
@media (48rem < width <= 54rem) {
  .shell-nav a .icon {
    display: none;
  }
}

@media (64rem < width <= 72rem) {
  .shell-nav:has(> a:nth-of-type(6)) a {
    padding: 0 var(--space-8);
    font-size: 0.75rem;
    letter-spacing: 0.06em;
  }

  .shell-header:has(.shell-nav > a:nth-of-type(6)) .btn-signout {
    min-width: var(--touch);
    padding: var(--space-8);
  }

  .shell-header:has(.shell-nav > a:nth-of-type(6)) .btn-signout .btn-label {
    display: none;
  }
}

@media (48rem < width <= 60rem) {
  .shell-nav:has(> a:nth-of-type(6)) a .icon {
    display: none;
  }
}

@media (48rem < width <= 52rem) {
  .shell-nav:has(> a:nth-of-type(6)) a {
    padding: 0 var(--space-6);
    letter-spacing: 0;
  }
}

@media (48rem < width <= 64rem) {
  .shell-nav a {
    padding: 0 var(--space-8);
    font-size: 0.75rem;
    letter-spacing: 0.06em;
  }

  .shell-header .btn-signout {
    min-width: var(--touch);
    padding: var(--space-8);
  }

  .btn-signout .btn-label {
    display: none;
  }
}

/* A phone held sideways is wide and short: the bar would take a third of
   the height, so the app nav stands as a rail on the left, under the
   header, and the header shrinks to one line. */
@media (width <= 64rem) and (height <= 30rem) and (orientation: landscape) {
  :root {
    --header-height: 3rem;
  }

  body:has(.shell-app) {
    padding-bottom: 0;
  }

  .shell-header {
    flex-wrap: nowrap;
    justify-content: space-between;
    gap: var(--space-12);
    min-height: var(--header-height);
    padding-block: var(--space-4);
  }

  .brand img {
    height: 28px;
  }

  .brand-name {
    font-size: 1.75rem;
  }

  .shell-app .shell-nav {
    position: fixed;
    top: var(--header-height);
    bottom: 0;
    left: 0;
    right: auto;
    z-index: 5;
    flex: none;
    flex-direction: column;
    flex-wrap: nowrap;
    justify-content: flex-start;
    gap: var(--space-4);
    width: calc(var(--rail) + env(safe-area-inset-left));
    height: auto;
    padding: var(--space-8) var(--space-4) var(--space-8) calc(var(--space-4) + env(safe-area-inset-left));
    background: var(--chrome);
    border-top: 0;
    border-right: 1px solid var(--chrome-line);
    box-shadow: 2px 0 8px rgb(10 25 47 / 0.25);
    overflow-y: auto;
    scrollbar-width: none;
  }

  .shell-app .shell-nav a {
    flex: none;
    flex-direction: column;
    justify-content: center;
    gap: var(--space-2);
    min-height: 3.25rem;
    padding: 0 var(--space-2);
    font-size: 0.75rem;
    letter-spacing: 0;
    text-transform: none;
    font-weight: 500;
    white-space: nowrap;
  }

  .shell-app .shell-nav a .icon {
    font-size: 1.5rem;
    opacity: 1;
  }

  .shell-app main {
    padding-left: calc(var(--rail) + env(safe-area-inset-left) + var(--gutter));
  }

  .shell-app .shell-footer {
    padding-left: calc(var(--rail) + env(safe-area-inset-left) + var(--gutter));
  }

  .shell-header .btn-signout {
    min-width: var(--touch);
    min-height: var(--touch);
    padding: var(--space-8);
  }

  .btn-signout .btn-label {
    display: none;
  }

  main {
    padding-bottom: var(--space-24);
  }
}

/* Desk: the console sections stand as a sidebar beside every console page. */

@media (width >= 64rem) {
  main:has(> .console-nav) {
    display: grid;
    grid-template-columns: 13rem minmax(0, 1fr);
    column-gap: var(--gap);
    align-items: start;
  }

  .console-nav,
  .console-nav:not(.console-home) {
    display: grid;
    grid-template-columns: none;
    gap: var(--space-8);
    position: sticky;
    top: calc(var(--header-height) + var(--gap));
    max-height: calc(100dvh - var(--header-height) - var(--gap) * 2);
    overflow-y: auto;
    /* As the list pane's: the padding holds focus rings inside the clip and
       the margin puts the entries on the header's edge. */
    margin: 0 calc(-1 * var(--space-4));
    padding: var(--space-4);
    background: transparent;
    border: 0;
    box-shadow: none;
  }

  .console-home > .console-group {
    display: block;
  }
}

/* With a mouse the sidebar's sixteen links fit a 900px-tall screen at 36px
   each, well over the 24px target minimum; at 44px the last group scrolled
   out of sight. */
@media (width >= 64rem) and (pointer: fine) {
  .console-group > a {
    min-height: 36px;
    padding-block: var(--space-4);
  }
}

@media (prefers-reduced-motion: reduce) {
  * {
    transition: none !important;
  }
}

/* Print: HR files the month list and a person's record. Chrome, navigation
   and actions go; tables and cards keep their rules in black on white. */

@media print {
  :root {
    color-scheme: light;
  }

  body {
    background: #fff;
    color: #000;
    padding: 0;
  }

  .shell-header,
  .shell-footer,
  .shell-nav,
  .skip-link,
  .console-nav,
  .list-pane,
  .pager,
  .actions,
  .btn,
  .card-link,
  .crumbs,
  .toast,
  form {
    display: none !important;
  }

  main {
    max-width: none;
    padding: 0;
  }

  .panes {
    display: block;
  }

  .card,
  .folds,
  .table-wrap {
    background: #fff;
    box-shadow: none;
    border-color: #999;
    break-inside: avoid;
  }

  .table-wrap {
    overflow: visible;
  }

  .table thead th {
    position: static;
  }

  a {
    color: inherit;
    text-decoration: none;
  }
}

/* Disclosures take the menus' chevron, right of the summary, so an open and
   a closed one look different. The empty alt text keeps the icon's name out
   of what a screen reader says. */
details:not(.account-menu, .bell) > summary {
  display: flex;
  align-items: center;
  gap: var(--space-6);
  list-style: none;
  cursor: pointer;
}

details:not(.account-menu, .bell) > summary::-webkit-details-marker {
  display: none;
}

details:not(.account-menu, .bell) > summary::after {
  content: "expand_more" / "";
  font-family: "Material Symbols Outlined";
  font-feature-settings: "liga";
  font-size: 1.25rem;
  line-height: 1;
  color: var(--muted-foreground);
  transition: transform 150ms ease-out;
}

details[open]:not(.account-menu, .bell) > summary::after {
  transform: rotate(180deg);
}

.leave-month > summary::after,
.fold > summary::after {
  margin-left: auto;
}

/* A card of folds keeps one frame under its title, and a rule divides each
   fold from the one above, so a month folded away reads as a row of the
   card. */
.folds {
  background: var(--card);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  margin-bottom: var(--space-20);
  box-shadow: var(--shadow-sm);
}

.fold {
  border-top: 1px solid var(--border);
}

.fold > summary {
  min-height: var(--touch);
  padding: var(--space-10) var(--card-inset);
  font-family: var(--font-heading);
  font-weight: 600;
  color: var(--heading);
}

.fold > .table-wrap {
  margin: 0;
  border: 0;
  border-radius: 0;
  box-shadow: none;
}

.fold:last-child > .table-wrap {
  border-radius: 0 0 var(--radius-lg) var(--radius-lg);
}

/* Two panes holding a table stack until the table fits beside the side card,
   so a row's actions never scroll out of sight; stacked, they follow source
   order. */
@container page (width >= 56rem) and (width < 84rem) {
  .panes:has(.table-wrap, > .pane-main .empty),
  .panes:has(.table-wrap, > .pane-main .empty):has(> .pane-main:first-child) {
    grid-template-columns: minmax(0, 1fr);
  }

  .panes:has(.table-wrap, > .pane-main .empty) > .pane-aside {
    max-width: var(--measure);
  }

  .panes:has(.table-wrap, > .pane-main .empty) > .pane-aside.pinned {
    position: static;
  }
}

/* The footer reaches the bottom of a short page: the shell's flex only takes
   effect once #root, between body and .shell, is a flex column too. */
#root {
  flex: 1 0 auto;
  display: flex;
  flex-direction: column;
}

/* A stamp not yet recorded recedes; a recorded time stays bold. */
.stamps dd.is-empty,
span.is-empty {
  color: var(--muted-foreground);
  font-weight: 400;
}

@media (width <= 48rem) {
  button.cal-day {
    min-height: calc(3.25rem - 8px);
  }
}

/* The team's two tables share their first four columns, so a fixed layout
   with the same widths lines them up one above the other. */
@container page (width >= 56rem) {
  .team-tables .table {
    table-layout: fixed;
  }

  .team-tables .table th:nth-child(1) {
    width: 26%;
  }

  .team-tables .table th:nth-child(2) {
    width: 30%;
  }

  .team-tables .table th:nth-child(3) {
    width: 16%;
  }

  .team-tables .table th:nth-child(4):not(:last-child) {
    width: 14%;
  }

  .team-tables .table td {
    white-space: normal;
    overflow-wrap: anywhere;
  }
}

/* Open warnings: each names what is wrong and, where the employee can fix
   it, the button that does. */
.warnings {
  margin: 0;
  padding: 0;
  list-style: none;
}

.warnings li {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-8) var(--space-12);
  padding: var(--space-10) 0;
  border-bottom: 1px solid var(--border);
}

.warnings li:last-child {
  border-bottom: 0;
}

.warnings li > span:not(.icon) {
  flex: 1 1 12rem;
}

.warnings .icon,
.bell-warnings .icon {
  color: var(--warning);
}

.bell-warnings {
  margin: 0;
  padding: 0;
  list-style: none;
}

.bell-warnings a {
  display: flex;
  align-items: center;
  gap: var(--space-8);
  min-height: var(--touch);
  padding: var(--space-8) var(--space-16);
  color: var(--foreground);
  text-decoration: none;
}

.bell-warnings a:hover {
  background: var(--row-hover);
}

/* Team today: the signed-in person's card reads like a colleague's tile,
   then everyone else by where they work. The head takes the rail's cap; the
   mode sits under the name and fills the row, ending where the pencils'
   bordered icons end, 4px past the rail's times. */
.team-me-head {
  box-sizing: content-box;
  max-width: 34rem;
  display: flex;
  flex-direction: column;
  gap: var(--space-12);
  padding-bottom: 0;
}

.team-me-head .today-status {
  margin-right: -4px;
}

.team-me-id {
  display: flex;
  align-items: center;
  gap: var(--space-10);
  min-width: 0;
}

.today-status form {
  position: relative;
}

/* The confirm row shows only while the select differs from the saved mode:
   the select never saves on change. A select holds only options, so the
   row lies over its value line, between the mode and the chevron. The
   select keeps the row's room on its right in both states, so its width,
   and the card's, never change with it. */
.mode-confirm {
  position: absolute;
  top: 1.75rem;
  right: var(--space-32);
  display: flex;
  align-items: center;
  height: 1.75rem;
  color: var(--muted-foreground);
  font-size: 0.75rem;
  pointer-events: none;
}

.mode-confirm > span {
  margin-right: var(--space-8);
}

.mode-confirm > .btn {
  margin: 0 -4px;
  pointer-events: auto;
}

.today-status form:not(:has(option:checked:not([selected]))) > .mode-confirm {
  display: none;
}

/* A narrow phone leaves the mode too little room beside the row, so the row
   drops under it and the box grows 2rem to hold it. The select's negative
   margin cancels the growth and the head's padding makes the room, so the
   picture and name stay put. */
@media (width <= 30rem) {
  .mode-confirm {
    top: 3.5625rem;
    right: var(--space-4);
    left: calc(var(--space-12) + 1px);
  }

  .mode-confirm > span {
    margin-right: auto;
  }

  .today-status form:has(option:checked:not([selected])) .input {
    margin-bottom: -2rem;
    padding-bottom: 2.75rem;
  }

  .team-me-head:has(option:checked:not([selected])) {
    padding-bottom: var(--space-32);
  }
}

/* Inside a field's box the buttons keep their 44px targets, which reach
   past the border, so hover and focus mark only the icon. */
:is(.mode-confirm, .rail-line.is-editing > form) > .btn:hover:not(:disabled) {
  background: none;
}

:is(.mode-confirm, .rail-line.is-editing > form) > .btn {
  padding: var(--space-6);
}

:is(.mode-confirm, .rail-line.is-editing > form) > .btn:focus-visible {
  outline: 0;
}

:is(.mode-confirm, .rail-line.is-editing > form) > .btn .icon {
  padding: var(--space-4);
  border: 1px solid color-mix(in srgb, var(--border) 50%, transparent);
  border-radius: var(--radius-sm);
  font-size: 1.125rem;
}

:is(.mode-confirm, .rail-line.is-editing > form) > .btn:hover .icon {
  background: var(--muted);
}

:is(.mode-confirm, .rail-line.is-editing > form) > .btn:focus-visible .icon {
  outline: 2px solid var(--ring);
}

.mode-confirm > [type="submit"],
.rail-line.is-editing > form > [type="submit"] {
  color: var(--success);
}

.today-status .field {
  position: relative;
  gap: var(--space-4);
  margin: 0;
}

.today-status .field > :first-child {
  color: var(--muted-foreground);
  font-size: 0.875rem;
  font-weight: 400;
  line-height: 1rem;
}

.today-status .input,
.today-status .mode-static {
  width: 100%;
  min-height: var(--touch);
  padding: var(--space-12) 2.25rem var(--space-12) var(--space-12);
  border: 1px solid var(--border-strong);
  border-radius: var(--radius);
  font-size: 1rem;
  font-weight: 500;
  line-height: 1.125rem;
}

.today-status .input {
  padding-right: 11rem;
}

@media (width <= 30rem) {
  .today-status .input {
    padding-right: 2.25rem;
  }
}

.today-status .mode-static {
  display: block;
  padding-right: var(--space-12);
}

.team-me-head .avatar,
.team-person .avatar {
  width: 40px;
  height: 40px;
}

/* A long name ellipsizes and keeps "(Me)" in view. */
.team-me-head .team-who > :first-child {
  display: flex;
  gap: 0.25em;
  max-width: 100%;
}

.team-me-head .team-who b {
  min-width: 0;
}

.team-me-tag {
  flex-shrink: 0;
  color: var(--muted-foreground);
  font-weight: 400;
}

.team-place {
  display: flex;
  align-items: center;
  gap: var(--space-8);
  margin: 0 0 var(--space-8);
  font-size: 1rem;
}

/* The one heading that keeps an icon: a colleague group's place. */
.team-place > .icon {
  color: var(--brand);
  margin-right: var(--space-2);
}

.team-grid + .team-place {
  margin-top: var(--gap);
}

.team-count {
  padding: 0 var(--space-8);
  border-radius: 999px;
  background: var(--muted);
  color: var(--muted-foreground);
  font-family: var(--font-body);
  font-size: 0.875rem;
  font-weight: 500;
}

.team-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(13rem, 1fr));
  gap: var(--space-8);
  margin: 0;
  padding: 0;
  list-style: none;
}

.team-person {
  display: flex;
  align-items: center;
  gap: var(--space-10);
  min-width: 0;
  padding: var(--space-10);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--card);
}

.team-who {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: var(--space-4);
  min-width: 0;
}

.team-who b {
  max-width: 100%;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.team-back {
  color: var(--muted-foreground);
  font-size: 0.8125rem;
}

/* Among colleagues green reads as "available"; a finished day is not. */
.team-person .badge-state-done {
  --state-surface: var(--neutral-surface);
  --state-ink: var(--muted-foreground);
}

/* Cards are size containers, which ignore their content's width; the
   person's own card measures its content so it never runs wider. Prose
   wraps to that width rather than setting it, and the mode's confirm row,
   the same-minute confirmation and a stamp's edit form lie inside it, so no
   change of state moves the colleagues beside it. Where the row has room
   the card fits the longest stop and its edit form on one line, "Início da
   pausa" in Portuguese. */
.team > .day-card {
  flex: 1 1 auto;
  container-type: normal;
  width: max-content;
  min-width: min(26rem, 100%);
  max-width: 34rem;
}

.team > .day-card :is(.day-lead > :not(.rail, .day-action), .stamp-confirm) {
  contain: inline-size;
}

/* Contained, the edit form takes its width from its basis: the input, its
   two buttons less their overlap, and its padding. Beside a label too long
   for the card's line it drops to a line of its own. */
.team > .day-card .rail-line.is-editing > form {
  contain: inline-size;
  flex: 0 1 calc(var(--rail-input) + 2 * var(--touch) - 10px);
}

/* The slack between a stop and its time is what the hugging card adds to
   its content. */
.team .rail-time {
  padding-left: var(--space-32);
}

/* The phone's card padding would double the day card's children's own, and
   the slack would narrow a time column the screen already narrows. */
@media (width <= 48rem) {
  .team > .day-card {
    padding: 0;
  }

  .team .rail-time {
    padding-left: 0;
  }
}
