/* ============================================================
   MANORA APPS — stylesheet + design-token MASTER
   This :root block is the ONE token source for the portal, every
   tool page and the style guide (../Manora_Web_Style_Guide.html
   mirrors it — keep the two one copy-paste apart). No other
   stylesheet may define :root tokens.
   ============================================================ */
/* Poppins, served from here (security review P18): every page used to
   ask fonts.googleapis.com for it, telling Google who opened what. The
   files are Google Fonts' own (v24; latin and latin-ext subsets of 300,
   400, 400 italic, 500 and 700, SIL Open Font License, OFL.txt beside
   them); the browser fetches only the subsets a page's text needs. They
   never change in place: another version is another file name, so
   /static/fonts/ is cached for a year (main.static_revalidate). */
@font-face {
  font-family: 'Poppins'; font-style: normal; font-weight: 300;
  font-display: swap;
  src: url("../fonts/poppins/poppins-light-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: 'Poppins'; font-style: normal; font-weight: 300;
  font-display: swap;
  src: url("../fonts/poppins/poppins-light-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: 'Poppins'; font-style: normal; font-weight: 400;
  font-display: swap;
  src: url("../fonts/poppins/poppins-regular-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: 'Poppins'; font-style: normal; font-weight: 400;
  font-display: swap;
  src: url("../fonts/poppins/poppins-regular-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: 'Poppins'; font-style: italic; font-weight: 400;
  font-display: swap;
  src: url("../fonts/poppins/poppins-regular-italic-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: 'Poppins'; font-style: italic; font-weight: 400;
  font-display: swap;
  src: url("../fonts/poppins/poppins-regular-italic-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: 'Poppins'; font-style: normal; font-weight: 500;
  font-display: swap;
  src: url("../fonts/poppins/poppins-medium-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: 'Poppins'; font-style: normal; font-weight: 500;
  font-display: swap;
  src: url("../fonts/poppins/poppins-medium-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: 'Poppins'; font-style: normal; font-weight: 700;
  font-display: swap;
  src: url("../fonts/poppins/poppins-bold-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: 'Poppins'; font-style: normal; font-weight: 700;
  font-display: swap;
  src: url("../fonts/poppins/poppins-bold-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;
}

:root {
  /* Colour — brand palette */
  --manora-blue:      #1068B2;
  --manora-deep-navy: #0B3252;
  --manora-sky:       #7BB6E0;
  --manora-amber:     #F4A93C;
  --manora-charcoal:  #231F20;
  --manora-slate:     #9D9FA2;  /* decorative/borders only — text uses --text-muted */
  --manora-mist:      #F4F6F8;
  --manora-white:     #FFFFFF;

  /* Colour — semantic */
  --text-muted:   #63666b;             /* muted text; ≥4.5:1 on white and Mist */
  --pass:         #2e7d43;
  --fail:         #b02a2a;
  --warn-text:    #9a6414;             /* warning text on white/amber tints */
  --line:         #e3e6ea;             /* hairlines, table + input borders */
  --pass-bg:      #e2f2e6;             /* PASS chip/banner surface */
  --pass-border:  #b9dcc2;
  --fail-bg:      #fbe9e9;             /* FAIL chip/banner surface */
  --error-bg:     #fdf1f1;             /* error/flash message surface */
  --error-border: #e8b5b5;
  --error-text:   #8a2b2b;
  --amber-hover:  #e2971f;             /* hover shade of Amber */
  --amber-tint-soft:   rgba(244, 169, 60, .12);
  --amber-tint:        rgba(244, 169, 60, .16);
  --amber-tint-strong: rgba(244, 169, 60, .35);
  --table-head:   #E7F0F8;             /* table.data header fill */
  --sheet-backdrop: #5b6670;           /* drawing-sheet preview surround */
  --seabed:       #8a6d3b;             /* seabed in the towing sketches */
  --dim:          #b9bbbe;             /* dimmed table rows (decorative) */
  --success-bg:   #eef7f0;             /* the "it is done" flash */
  --success-text: #1e5c31;
  --blue-tint:      rgba(16, 104, 178, .12);  /* badge-live, a ticked chip's inset, provenance chips */
  --blue-tint-soft: rgba(16, 104, 178, .06);  /* a ticked chip's fill */
  --focus-ring:       0 0 0 3px rgba(16, 104, 178, .15);      /* every :focus-visible */
  --focus-ring-inset: inset 0 0 0 2px rgba(16, 104, 178, .35); /* an input inside a table cell */
  --on-dark-line:  rgba(123, 182, 224, .4);   /* dividers and outlines on the navy bars */
  --on-dark-hover: rgba(123, 182, 224, .18);
  --on-dark-focus: rgba(123, 182, 224, .35);
  --shadow-raised:  0 6px 18px rgba(11, 50, 82, .14);  /* a card lifting on hover, a drop-down list */
  --shadow-overlay: 0 10px 30px rgba(11, 50, 82, .18); /* the sign-in card, a hint panel, a dialog */
  --shadow-knob:    0 1px 2px rgba(0, 0, 0, .25);      /* the switch's knob */
  --shadow-paper:   0 6px 24px rgba(0, 0, 0, .45);     /* the drawing sheet on its backdrop */
  --scrim:          rgba(11, 50, 82, .35);             /* behind a dialog */
  --label-ground:   rgba(255, 255, 255, .86);          /* a name box over ink on a chart or map */
  --photo-shade:    rgba(11, 50, 82, .82);             /* the foot of a photo a caption sits on (Reference Projects' tiles) */
  --selection:      var(--manora-amber);               /* the ring round a selected marker */

  /* Colour — ink on drawings (canvas and SVG read these through
     ManoraUI.ink(); the categorical set is the cargo palette's order,
     which is stored in records and must not change) */
  --cat-1: #B02A2A; --cat-2: #1068B2; --cat-3: #2E7D43; --cat-4: #B07515;
  --cat-5: #6B4D9E; --cat-6: #0B8080; --cat-7: #C2185B; --cat-8: #5D4037;
  --cat-steel: #33557f;   /* outlines and markers on a GA plan (the side view) */
  --cat-line:  #8b1a1a;   /* mooring lines, the front view */
  --pass-light: #7fb069;  /* the unloaded waterline beside the loaded one */
  --quay:  #d9d2c5;       /* the quay on the berth plan */
  --hatch: #cfd4da;       /* deck hatching */
  --hold-wall: #dfe3e8;   /* the hold's walls and the ship's sides in
                             the seafastening views: sf_figures.py's
                             WALL, so the page and the report agree */

  /* Typography — ONE scale of ten steps (UI overhaul 2026-09;
     ui-standard §12): every font size of the portal and the tools
     names a step */
  --font-primary: 'Poppins', Arial, sans-serif;
  --font-mono: 'SF Mono', Menlo, Consolas, monospace;
  /* the desktop widget (app/desktop_widget.jsx, after Apple's Stocks
     widget) and its preview on the account page: a dark card in the
     Mac's own font and colours, written out in the widget file too */
  --font-system: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', Arial, sans-serif;
  --widget-bg:     #1c1c1e;
  --widget-text:   #FFFFFF;
  --widget-muted:  rgba(235, 235, 245, .6);
  --widget-line:   rgba(255, 255, 255, .12);
  --widget-up:     #ff453a;   /* a price up: a cost up, so red */
  --widget-down:   #30d158;
  --widget-blue:   #0a84ff;
  --widget-warn:   #ffd60a;
  --widget-button: rgba(255, 255, 255, .14);
  --fs-2xs: 11px;      /* uppercase group titles, sub-lines, chart ticks */
  --fs-xs:  12.5px;    /* hints, dense table cells, chips */
  --fs-sm:  13px;      /* form labels, small buttons, callouts, pills */
  --fs-base: 14px;     /* tool body, portal table cells and small text */
  --fs-md:  15px;      /* tool h3, the topbar brand */
  --fs-lg:  16px;      /* portal body, the sign-in card */
  --fs-xl:  18px;      /* stat values, portal h4 */
  --fs-2xl: 24px;      /* tool h2, portal h3 */
  --fs-3xl: 32px;      /* portal h2 */
  --fs-4xl: 44px;      /* portal h1 */
  --fw-regular: 400;
  --fw-medium: 500;
  --fw-bold: 700;      /* Poppins ships no 600: it renders as this */
  --lh-tight: 1.2;
  --lh-body: 1.5;
  --lh-portal: 1.6;
  --tracking-caps: .05em;

  /* Spacing + radius + layout. --space-unit is the documented 8 px
     grid; the --sp-* steps name the rhythm the pages really use
     (shared.md §3.6), 10 px included: it is the tool row gap. */
  --space-unit: 8px;
  --sp-1: 2px;  --sp-2: 4px;  --sp-3: 6px;  --sp-4: 8px;  --sp-5: 10px;
  --sp-6: 12px; --sp-8: 16px; --sp-12: 24px; --sp-16: 32px;
  --sp-24: 48px; --sp-32: 64px;
  --radius: 6px;
  --radius-sm: 4px;
  --radius-xs: 2px;
  --radius-pill: 999px;
  --radius-round: 50%;
  --page-max: 1280px;         /* every page column (portal and tools) */
}

/* the hidden attribute wins over any display rule, so no stylesheet
   needs its own "[hidden] { display: none }" for a flex or grid box */
[hidden] { display: none !important; }

* { margin: 0; padding: 0; box-sizing: border-box; }

body {
  font-family: var(--font-primary);
  font-size: var(--fs-lg);
  color: var(--manora-charcoal);
  background: var(--manora-mist);
  line-height: 1.6;
  min-height: 100vh;
  display: flex;
  flex-direction: column;
}

h1 { font-size: var(--fs-4xl); font-weight: 700; line-height: 1.15; }
h2 { font-size: var(--fs-3xl); font-weight: 700; line-height: 1.2; color: var(--manora-blue); }
h3 { font-size: var(--fs-2xl); font-weight: 700; line-height: 1.25; }
h4 { font-size: var(--fs-xl); font-weight: 500; line-height: 1.3; }
.small { font-size: var(--fs-base); color: var(--text-muted); }

a.link { color: var(--manora-blue); text-decoration: underline; text-underline-offset: 3px; }
a.link:hover { color: var(--manora-deep-navy); }
a.link-dark { color: var(--manora-sky); text-decoration: underline; text-underline-offset: 3px; }
a.link-dark:hover { color: var(--manora-white); }

@media (max-width: 640px) {
  h1 { font-size: var(--fs-3xl); }
  h2 { font-size: 26px; }
}

/* ------------------------------------------------ buttons
   One family (ui-overhaul choice C3), current values, no redesign:
   - .btn (+ .btn-primary / .btn-secondary, .btn-block): the 16 px call
     to action of the sign-in cards, sized for a finger on an iPad;
   - .btn.btn-compact: a form's button on an app page (account, admin,
     the placeholder): the tool base button's size and look — 14 px,
     6 × 12, a 1 px border; .btn-primary is its blue fill, .btn-secondary
     the plain white one that turns blue on hover;
   - button.sm: a button in a table row or a caption (SHARED COMPONENTS
     at the end of this file);
   - button.linky: a button that reads as a link, in the size of the
     text around it; .link-btn is the same at the hint size (12.5 px).
   Every one of them takes the focus ring (button:focus-visible below). */
.btn {
  display: inline-block;
  font-family: var(--font-primary);
  font-size: var(--fs-lg); font-weight: 500;
  padding: 12px 28px;
  border-radius: var(--radius);
  border: 2px solid transparent;
  cursor: pointer;
  text-decoration: none;
  text-align: center;
  transition: background .15s ease, color .15s ease, border-color .15s ease;
}
.btn-primary { background: var(--manora-blue); color: var(--manora-white); }
.btn-primary:hover { background: var(--manora-deep-navy); }
.btn-secondary { background: none; color: var(--manora-blue); border-color: var(--manora-blue); }
.btn-secondary:hover { background: var(--manora-blue); color: var(--manora-white); }
.btn:disabled {
  background: var(--manora-mist); color: var(--text-muted);
  border-color: transparent; cursor: not-allowed;
}
.btn-block { display: block; width: 100%; }

/* ------------------------------------------------ forms */
.field { margin-bottom: calc(var(--space-unit) * 2); }
.field label {
  display: block;
  font-size: var(--fs-base);
  font-weight: 500;
  margin-bottom: 4px;
}
.field input, .field select {
  width: 100%;
  font-family: var(--font-primary);
  font-size: var(--fs-lg);
  color: var(--manora-charcoal);
  padding: 11px 14px;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--manora-white);
  transition: border-color .15s ease, box-shadow .15s ease;
}
.field input:focus, .field select:focus {
  outline: none;
  border-color: var(--manora-blue);
  box-shadow: var(--focus-ring);
}
.field .hint { font-size: var(--fs-xs); color: var(--text-muted); margin-top: 4px; }
.check-row {
  display: flex; align-items: center; gap: 8px;
  font-size: var(--fs-base); color: var(--manora-charcoal);
  cursor: pointer; user-select: none;
  margin-bottom: calc(var(--space-unit) * 2);
}
.check-row input { accent-color: var(--manora-blue); cursor: pointer; }
/* "Stay signed in" is a switch (the .switch component below) in the
   check-row's place, at the card's text size */
.switch.check-row { display: flex; font-size: var(--fs-base); }

/* ------------------------------------------------ flash messages */
.flash {
  border-radius: var(--radius);
  padding: 12px 16px;
  font-size: var(--fs-base);
  margin-bottom: calc(var(--space-unit) * 2);
  border: 1px solid;
}
.flash-error   { background: var(--error-bg); border-color: var(--error-border); color: var(--error-text); }
.flash-success { background: var(--success-bg); border-color: var(--pass-border); color: var(--success-text); }
.flash-warn    { background: var(--amber-tint-soft); border-color: var(--amber-tint-strong); color: var(--warn-text); }
/* a Daily Progress Report running on its own clock (the dashboard's
   top): a standing notice, one line a report */
.dpr-banner { font-size: var(--fs-base); padding: 10px 14px; margin: 0 0 12px; }
.dpr-banner a { color: inherit; font-weight: 700; }

/* live password feedback (static/js/password_hint.js) — two classes,
   so it outweighs `.field .hint`'s muted colour */
.pw-hint.pw-bad  { color: var(--error-text); }
.pw-hint.pw-weak { color: var(--warn-text); }
.pw-hint.pw-good { color: var(--pass); }

/* ------------------------------------------------ auth layout (login / register) */
.auth-page {
  flex: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 48px 24px;
  background:
    linear-gradient(180deg, var(--manora-deep-navy) 0 260px, var(--manora-mist) 260px);
}
.auth-card {
  width: 100%;
  max-width: 420px;
  background: var(--manora-white);
  border-radius: var(--radius);
  border: 1px solid var(--line);
  box-shadow: var(--shadow-overlay);
  padding: 40px 36px 32px;
}
.auth-card .logo { display: block; height: 54px; margin: 0 auto 20px; }
.auth-card h3 { text-align: center; margin-bottom: 4px; }
.auth-card .sub {
  text-align: center;
  font-size: var(--fs-base);
  color: var(--text-muted);
  margin-bottom: calc(var(--space-unit) * 3);
}
.auth-card form { margin-top: calc(var(--space-unit) * 2); }
/* "or" between the passkey button and the password form (login) */
.auth-or {
  display: flex; align-items: center; gap: 12px;
  margin: calc(var(--space-unit) * 2) 0;
  font-size: var(--fs-base); color: var(--text-muted);
}
.auth-or::before, .auth-or::after {
  content: ""; flex: 1; border-top: 1px solid var(--line);
}
/* what a passkey page says while it waits for the device */
.pk-status:empty { display: none; }
.auth-card .pk-lead, .auth-card .lead { font-size: var(--fs-base); margin-bottom: calc(var(--space-unit) * 2); }
.auth-card .pk-lead strong, .auth-card .lead strong { font-weight: 500; }
.auth-links {
  margin-top: calc(var(--space-unit) * 3);
  padding-top: calc(var(--space-unit) * 2);
  border-top: 1px solid var(--line);
  text-align: center;
  font-size: var(--fs-base);
}

/* ------------------------------------------------ app header / footer
   The topbar, the page and the footer share one column (--page-max, the
   tools' width too, ui-overhaul choice C2) and one 24 px inset, so the
   logo, the headings and the footer's text start on the same line. */
.topbar { background: var(--manora-deep-navy); }
.topbar .inner {
  max-width: var(--page-max); margin: 0 auto;
  padding: 14px 24px;
  display: flex; align-items: center; justify-content: space-between; gap: 16px;
}
.topbar .brand { display: flex; align-items: center; gap: 14px; text-decoration: none; }
.topbar .brand img { height: 34px; display: block; }
.topbar .brand span {
  color: var(--manora-sky);
  font-size: var(--fs-base);
  border-left: 1px solid var(--on-dark-line);
  padding-left: 14px;
  letter-spacing: .06em;
  text-transform: uppercase;
  font-weight: 500;
}
.topbar nav { display: flex; align-items: center; gap: 20px; font-size: var(--fs-base); }
.topbar nav .who { color: var(--manora-white); }
/* Sign out is a POST (security review A5): a button dressed as the
   topbar's links */
.topbar nav form { display: contents; }
.topbar nav button.link-dark {
  background: none; border: 0; padding: 0; cursor: pointer;
  font: inherit; color: var(--manora-sky);
  text-decoration: underline; text-underline-offset: 3px;
}
.topbar nav button.link-dark:hover { color: var(--manora-white); }

/* The same links at the right end of a tool page's #topbar: app/main.py
   tool_index puts them there (ui-overhaul choice C8), after the tool's
   own controls, a hairline between the two; on a narrow screen they wrap
   onto a line of their own. The tool skin's button rules are undone for
   the Sign out button, which reads as a link here too. */
#topbar .topbar-user {
  display: flex; align-items: center; flex-wrap: wrap; gap: 6px 16px;
  margin-left: auto; font-size: var(--fs-sm);
}
#topbar #project-indicator ~ .topbar-user, #topbar #credits-state ~ .topbar-user {
  margin-left: 0; padding-left: 16px; border-left: 1px solid var(--on-dark-line);
}
#topbar .topbar-user .who { color: var(--manora-white); }
#topbar .topbar-user form { display: contents; }
#topbar .topbar-user button.link-dark {
  background: none; border: 0; padding: 0; cursor: pointer; font: inherit;
  color: var(--manora-sky); text-decoration: underline; text-underline-offset: 3px;
}
#topbar .topbar-user button.link-dark:hover { color: var(--manora-white); background: none; }
#topbar .topbar-user a:focus-visible, #topbar .topbar-user button:focus-visible {
  box-shadow: 0 0 0 3px var(--on-dark-focus); border-radius: var(--radius-sm);
}

main.page {
  flex: 1;
  width: 100%;
  max-width: var(--page-max);
  margin: 0 auto;
  padding: 48px 24px 64px;
}
.page-head { margin-bottom: calc(var(--space-unit) * 4); }
.page-head p { color: var(--text-muted); max-width: 620px; }

footer.site {
  background: var(--manora-deep-navy);
  color: var(--manora-sky);
  padding: 20px 0;
  font-size: var(--fs-base);
}
footer.site .inner {
  max-width: var(--page-max); margin: 0 auto; padding: 0 24px;
  display: flex; justify-content: space-between; flex-wrap: wrap; gap: 8px;
}
footer.site strong { color: var(--manora-white); }

/* ------------------------------------------------ dashboard grid */
.tool-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
  gap: calc(var(--space-unit) * 3);
}
/* A second group heading sits as far below the grid above it as the first
   one sits below the top of the page, so every group is spaced alike. */
.tool-grid + .page-head { margin-top: calc(var(--space-unit) * 6); }
.tool-card {
  display: flex;
  flex-direction: column;
  background: var(--manora-white);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 24px;
  text-decoration: none;
  color: inherit;
  transition: transform .12s ease, box-shadow .12s ease;
}
a.tool-card:hover { transform: translateY(-2px); box-shadow: var(--shadow-raised); }
/* The dashboard's tile is a card whose title link is stretched over the
   whole of it (::after), so the tile clicks as one while the hint dot
   beside its badge stays a button of its own, above the link. (Market
   Rates' tiles are whole links, a.tool-card above.) */
.tool-card { position: relative; }
.tool-card a.stretch { color: inherit; text-decoration: none; }
.tool-card a.stretch::after {
  content: ""; position: absolute; inset: 0; border-radius: var(--radius);
}
.tool-card .hint-dot { position: relative; z-index: 1; }
/* the foot at the tile's bottom, a description or none */
div.tool-card > .foot { margin-top: auto; padding-top: 18px; }
.tool-card:has(a.stretch:hover) { transform: translateY(-2px); box-shadow: var(--shadow-raised); }
.tool-card a.stretch:focus-visible { box-shadow: none; }
.tool-card:has(a.stretch:focus-visible) { border-color: var(--manora-blue); box-shadow: var(--focus-ring); }
.tool-card .icon {
  width: 48px; height: 48px;
  border-radius: var(--radius);
  background: var(--manora-mist);
  color: var(--manora-blue);
  display: flex; align-items: center; justify-content: center;
  margin-bottom: 16px;
}
.tool-card .icon svg { width: 26px; height: 26px; }
.tool-card h4 { font-weight: 700; font-size: var(--fs-xl); margin-bottom: 6px; color: var(--manora-deep-navy); }
.tool-card p { font-size: var(--fs-base); color: var(--manora-charcoal); flex: 1; }
.tool-card .foot { margin-top: 18px; display: flex; align-items: center; justify-content: space-between; }
.badge {
  display: inline-block;
  font-size: 12px; font-weight: 500;
  padding: 3px 12px;
  border-radius: var(--radius-pill);
  white-space: nowrap;
}
.badge-soon { background: var(--amber-tint); color: var(--warn-text); }
.badge-live { background: var(--blue-tint); color: var(--manora-blue); }
/* not known yet (wait), or an ordinary state that is not on (off: a
   User beside an Admin) — never amber, which asks to be looked at */
.badge-wait, .badge-off { background: var(--manora-mist); color: var(--text-muted); }
.tool-card .open { font-size: var(--fs-base); font-weight: 500; color: var(--manora-blue); }

/* a tile that cannot be opened yet: quiet, but its pill keeps the
   contrast it needs (a faded card took the amber text under 4.5:1) */
.tool-card.tool-locked { background: none; }
.tool-card.tool-locked .icon { filter: grayscale(1); opacity: .6; }
.tool-card.tool-locked h4, .tool-card.tool-locked p { color: var(--text-muted); }

/* ------------------------------------------------ plain content card (account, admin, placeholder) */
/* full page width everywhere — a form field inside keeps its own width
   (.card .field), so a card never has to be narrowed by hand */
.card {
  background: var(--manora-white);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 32px;
}
.card + .card { margin-top: calc(var(--space-unit) * 3); }
.card h3 { margin-bottom: 16px; }
.card .field { max-width: 420px; }
/* a card is the page column wide (--page-max); its prose keeps a
   reading measure, as the page head's lead does */
main.page .card p { max-width: 640px; }
/* a line of text between a card's heading and its table */
.card .card-intro { margin-bottom: calc(var(--space-unit) * 1.5); }
/* On an app page (account) a form field is the app's size, as tall as
   the compact button under it and the one-line forms beside it; the
   sign-in cards keep 16 px, which iPad Safari does not zoom into. */
main.page .field input, main.page .field select {
  font-size: var(--fs-base); line-height: 1.5; padding: 6px 9px;
}
/* a row of buttons under a card's text (the placeholder's way back) */
.card .actions { margin-top: calc(var(--space-unit) * 2); }

/* ------------------------------------------------ admin tables */
.table-scroll { overflow-x: auto; margin-bottom: 8px; }
table.list { border-collapse: collapse; width: 100%; margin-bottom: 8px; }
.table-scroll table.list { margin-bottom: 0; }
table.list th, table.list td {
  border-bottom: 1px solid var(--line);
  padding: 9px 10px; font-size: var(--fs-base); text-align: left;
  vertical-align: middle;
  white-space: nowrap;
}
table.list td:first-child, table.list th:first-child { padding-left: 0; }
table.list th { color: var(--manora-deep-navy); font-weight: 700; }
/* a subheading inside a table: one cell across the row (a th with
   scope="rowgroup" heading its own tbody), set like the head but with
   air above it, so the rows below read as its group */
table.list tr.group-row > td, table.list tr.group-row > th {
  padding-top: 18px; padding-bottom: 6px;
  color: var(--manora-deep-navy); font-weight: 700;
  border-bottom: 1px solid var(--line);
}
table.list tr:first-child + tr.group-row > td,
table.list thead + tbody > tr.group-row:first-child > * { padding-top: 9px; }
table.list td.right { text-align: right; }
/* the portal's tables end flush with the card, as they start, so the
   action buttons line up under the Copy caption */
main.page table.list td:last-child, main.page table.list th:last-child { padding-right: 0; }
table.list form { margin: 0; display: inline; }
/* The admin page's detail rows (docs/ui-standard.md §10.3): the summary
   pill is the shared .disc-toggle, the panel the shared .disc-panel
   (both below, in the components moved up from the tool skin), folded
   by static/js/manora_disclosure.js. */

/* An open panel is prose, not a table cell: it wraps inside the width the
   closed table already has, so opening one never widens the table or puts
   a sentence behind a sideways scroll. */
table.list tr.disc-panel-row > td {
  padding: 0 0 16px;
  border-bottom: 1px solid var(--line);
  white-space: normal;
}
.disc-panel-row .disc-panel {
  display: block;              /* beats table.list form { display: inline } */
  margin: 0; padding: 14px 16px 12px;
  background: var(--manora-mist);
  border: 1px solid var(--line); border-left: 3px solid var(--manora-blue);
  border-radius: var(--radius);
}
/* a panel that saves itself (the module picker): dimmed while it saves,
   red when a save failed and its Save button is back */
.disc-panel.saving { opacity: .65; }
.disc-panel.save-failed {
  border-color: var(--error-border); background: var(--error-bg);
}
.disc-panel-row .disc-panel p { max-width: 620px; }
/* manora_disclosure.js runs in <head> and marks <html class="disc-js">:
   a panel it is about to fold stays out of the first paint and its
   toggle reads closed; without JavaScript both show as rendered, open */
html.disc-js [data-disc-panel]:not([data-disc-ready]) { display: none; }
html.disc-js [data-disclosure]:not([data-disc-ready]) .chev { transform: none; }
html.disc-js .disc-toggle[data-disclosure]:not([data-disc-ready]):not(.warn) {
  border-color: var(--line); color: var(--manora-charcoal);
}
.mod-lead {
  font-size: var(--fs-xs); color: var(--text-muted);
  text-transform: uppercase; letter-spacing: .04em; margin-bottom: 10px;
}
/* Map data card (admin): the facts inside a map's panel, and the bar a
   137 GB download fills. Both live in the .disc-panel shell above. */
.map-facts {
  display: grid; grid-template-columns: auto 1fr; gap: 4px 14px;
  margin: 10px 0; font-size: var(--fs-sm);
}
.map-facts dt { color: var(--text-muted); }
.map-facts dd { margin: 0; overflow-wrap: anywhere; }
.map-progress {
  height: 6px; margin: 10px 0 6px;
  background: var(--line); border-radius: var(--radius-pill);
  overflow: hidden;
}
.map-progress span {
  display: block; height: 100%;
  background: var(--manora-blue); border-radius: var(--radius-pill);
  transition: width .4s ease;
}
.map-progress-text { color: var(--text-muted); }

/* VesselFinder credits card (admin): the account line, and the
   who-spent-what lists inside a method's panel. Its facts grids are
   the map card's, above — same shape, so same rule. */
.vf-state {
  display: flex; flex-wrap: wrap; align-items: baseline; gap: 6px 12px;
  margin-bottom: 2px;
}
.vf-balance { font-size: var(--fs-xl); font-weight: 700; color: var(--manora-deep-navy); }
.vf-facts { max-width: 520px; }
.vf-split {
  list-style: none; margin: 0 0 6px; padding: 0;
  max-width: 520px; font-size: var(--fs-sm);
}
.vf-split li {
  display: flex; justify-content: space-between; gap: 16px;
  padding: 4px 0; border-bottom: 1px solid var(--line);
}
.vf-split li:last-child { border-bottom: 0; }
.vf-split li span:last-child { color: var(--text-muted); white-space: nowrap; }

/* The spend summary and the 30-day chart sit side by side while there
   is room, and stack when there is not. */
.vf-grid {
  display: grid; gap: 8px 32px; align-items: start;
  /* min() and not a bare 300px: on a narrow screen a 300px track is
     wider than the card and spills out of it, clipped rather than
     scrollable. Capped at 100% the pair simply stacks. */
  grid-template-columns: repeat(auto-fit, minmax(min(300px, 100%), 1fr));
  margin-bottom: 18px;
}
.vf-grid .vf-facts { max-width: none; }
/* a heading inside an admin card: the credits card's, and the Contacts
   card's import preview (.card-subhead is the general name) */
.vf-subhead, .card-subhead {
  font-size: var(--fs-xl); font-weight: 700; color: var(--manora-deep-navy);
  margin: 22px 0 10px;
}

/* One column per day, spent or not: a flat run of stubs is a fortnight
   nobody asked the API anything, which is worth seeing. */
.vf-chart {
  display: flex; align-items: flex-end; gap: 2px;
  height: 68px; margin-top: 4px;
  border-bottom: 1px solid var(--line);
}
.vf-col {
  flex: 1 1 0; display: flex; align-items: flex-end; height: 100%;
  min-width: 3px;
}
.vf-col > span {
  display: block; width: 100%; min-height: 2px;
  background: var(--manora-sky);
  border-radius: var(--radius-sm) var(--radius-sm) 0 0;
}
.vf-col.today > span { background: var(--manora-blue); }
.vf-col.zero > span { background: var(--line); }
.vf-axis {
  display: flex; justify-content: space-between;
  font-size: var(--fs-xs); color: var(--text-muted); margin-top: 5px;
}

/* The bar beside a figure is always relative to the biggest figure in
   its own table — never a share of the total (app/vf_usage.py _bar). */
.vf-bar-col { width: 22%; min-width: 90px; }
.vf-meter {
  display: block; height: 8px; width: 100%;
  background: var(--manora-mist); border: 1px solid var(--line);
  border-radius: var(--radius-pill); overflow: hidden;
}
.vf-meter > span {
  display: block; height: 100%; min-width: 2px;
  background: var(--manora-blue); border-radius: var(--radius-pill);
}
/* The one exception: in "Today's limits" a full bar is the row's own
   daily cap (app/vf_budget.py), and it turns amber at the share where
   the owner is mailed. */
.vf-meter.near > span { background: var(--manora-amber); }
/* its rows stay bare <tr><td><td> (tests/test_vf_budget.py reads
   them), so its number column is set from the table */
table.vf-limits td:nth-child(2) { text-align: right; font-variant-numeric: tabular-nums; }

/* The Server card (admin): the map card's table with one row per part
   of the Pi, a disk bar in the basemap's progress bar, and the log of
   an action in progress. The state lives in the pill, never in the
   colour of a value. */
.host-note { margin: 0 0 12px; }
table.list td.host-detail { white-space: normal; min-width: 260px; }
.host-disk {
  display: inline-block; vertical-align: middle;
  width: 110px; margin: 0 0 2px 10px;
}
.host-disk.is-soon span { background: var(--warn-text); }
.host-job { margin-top: 14px; }
.host-job .small { display: flex; align-items: center; gap: 10px; margin-bottom: 8px; }
.host-log {
  margin: 0; padding: 10px 12px; max-height: 240px; overflow: auto;
  background: var(--manora-mist); border: 1px solid var(--line);
  border-radius: var(--radius); font-size: var(--fs-xs); line-height: 1.45;
  white-space: pre-wrap; overflow-wrap: anywhere;
}
.host-last { margin-top: 12px; }
.host-last summary { cursor: pointer; color: var(--text-muted); }
.host-last .host-log { margin-top: 8px; }

/* The module picker's chips are the shared tick chips (.tick-chip,
   below) as a grid: a cell per application, the name taking the width,
   so an "Under development" pill sits at the chip's end. Select all and
   Clear need the script; the plain form (no JavaScript) has its boxes
   and Save. */
.tick-chips.grid {
  display: grid; gap: 8px;
  grid-template-columns: repeat(auto-fill, minmax(230px, 1fr));
}
.tick-chips.grid .tick-chip { display: flex; padding: 8px 12px; }
/* inside a table.list, whose .nm is a bold record name */
.tick-chips.grid .tick-chip .nm { flex: 1; font-weight: 400; color: var(--manora-charcoal); }
.tick-chip .badge { font-size: var(--fs-2xs); padding: 2px 7px; }
html:not(.disc-js) [data-mod-all], html:not(.disc-js) [data-mod-none] { display: none; }
.mod-actions {
  display: flex; align-items: center; gap: 14px; margin-top: 12px;
}
.mod-state { font-size: var(--fs-xs); color: var(--text-muted); }
/* .link-btn: button.linky (below) at the small size it has always had */
.link-btn { font-size: var(--fs-xs); }

/* ------------------------------------------------ hint dot + panel
   The one way to explain something in the UI (static/js/manora_hint.js):
   <button class="hint-dot" data-hint="..."></button>. Never title="". */
.hint-dot {
  display: inline-flex; align-items: center; justify-content: center;
  flex: none; width: 16px; height: 16px; padding: 0;
  font-family: var(--font-primary); font-size: var(--fs-2xs); font-weight: 700;
  font-style: italic; line-height: 1;
  color: var(--manora-blue); background: var(--manora-white);
  border: 1.5px solid var(--manora-blue); border-radius: 50%;
  cursor: pointer; vertical-align: middle;
  transition: background .15s ease, color .15s ease;
}
.hint-dot::before { content: "i"; }
/* the dot keeps its distance from the word before it wherever it sits
   (a badge, a heading, a table head, a label) without leaning on a
   space in the source: a label or a th built in JS has none. A flex
   row with a gap of its own (the switch, a tick chip) spaces it already. */
.badge + .hint-dot, h3 .hint-dot, h4 .hint-dot, th .hint-dot,
label:not(.switch):not(.tick-chip) > .hint-dot, dl.specs dt > .hint-dot { margin-left: 6px; }
/* .foot is space-between: keep the dot next to its badge, not adrift */
.tool-card .foot .hint-dot { margin-right: auto; }
.hint-dot:hover,
.hint-dot[aria-expanded="true"] { background: var(--manora-blue); color: var(--manora-white); }
.hint-dot:focus-visible { outline: 2px solid var(--manora-blue); outline-offset: 2px; }

.hint-pop {
  position: fixed; margin: 0; inset: auto; z-index: 60;
  width: max-content; max-width: min(320px, calc(100vw - 32px));
  padding: 11px 14px;
  font-family: var(--font-primary); font-size: var(--fs-sm); line-height: 1.5;
  color: var(--manora-charcoal); background: var(--manora-white);
  border: 1px solid var(--line); border-radius: var(--radius);
  box-shadow: var(--shadow-overlay);
  opacity: 0; transform: translateY(-3px);
  transition: opacity .12s ease, transform .12s ease;
}
.hint-pop.open { opacity: 1; transform: none; }
/* only the no-Popover-API fallback needs display juggling; with the API
   the UA rule [popover]:not(:popover-open) does it (and gives us the
   top layer, so .table-scroll can't clip the panel) */
.hint-pop:not([popover]) { display: none; }
.hint-pop:not([popover]).shown { display: block; }
/* text for a screen reader only: a hint dot's whole text, read out on
   a click when its name is the first sentence (manora_hint.js) */
.sr-only {
  position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0;
  overflow: hidden; clip-path: inset(50%); white-space: nowrap; border: 0;
}
.hint-pop::after {
  content: ""; position: absolute; left: var(--arrow-x, 50%); top: -5px;
  width: 8px; height: 8px; margin-left: -4px;
  background: var(--manora-white);
  border-left: 1px solid var(--line); border-top: 1px solid var(--line);
  transform: rotate(45deg);
}
.hint-pop.above::after {
  top: auto; bottom: -5px;
  border: 0; border-right: 1px solid var(--line);
  border-bottom: 1px solid var(--line);
}

/* an empty list's card (the dashboard, the templates page): as wide
   as every card (ui-standard §10.1), naming the way out */
.empty-state p { color: var(--text-muted); font-size: var(--fs-base); }
.inline-form { display: flex; align-items: center; gap: 10px;
  margin-top: 12px; flex-wrap: wrap; }
.inline-form input[type="email"], .inline-form input[type="text"] {
  flex: 1 1 240px; max-width: 340px;
  font-family: var(--font-primary); font-size: var(--fs-base); line-height: 1.5;
  padding: 6px 9px; border: 1px solid var(--line);
  border-radius: var(--radius); color: var(--manora-charcoal);
}
.inline-form input[type="email"]:focus, .inline-form input[type="text"]:focus {
  outline: none; border-color: var(--manora-blue);
  box-shadow: var(--focus-ring);
}

/* the account page's desktop widget card (account_widget.js): a figure
   per row, its series and port side by side; the install steps, the
   key's buttons, the preview's graph under its tiles */
[data-widget] h4 { margin: 24px 0 10px; font-size: var(--fs-base); font-weight: 700; }
[data-widget] h4:first-of-type { margin-top: 0; }
.card [data-widget] .field.widget-wide { max-width: 720px; }
[data-widget] p > .hint-dot { margin-left: 6px; }
.widget-items { display: grid; gap: 8px; margin-bottom: 8px; }
.widget-item { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.field .widget-item select { width: auto; min-width: 0; flex: 1 1 180px; max-width: 280px; }
/* the switch keeps its own label (a .field's would make it a block) */
.widget-switch { margin-bottom: calc(var(--space-unit) * 2); }
.widget-switch .switch { font-size: var(--fs-base); font-weight: 500; }
.widget-steps { margin: 0 0 8px 20px; font-size: var(--fs-base); }
.widget-steps li + li { margin-top: 4px; }
.widget-buttons { display: flex; gap: 8px; flex-wrap: wrap; margin-top: 8px; }
/* .wpv: the preview, a drawing of the desktop widget as
   app/desktop_widget.jsx draws it (after Apple's Stocks widget), on a
   stand-in for the desktop; the sizes are the widget's */
.wpv-desk {
  display: flex; padding: 28px; margin-bottom: 8px; border-radius: var(--radius);
  background: linear-gradient(135deg, var(--manora-deep-navy), var(--manora-blue));
}
.wpv-card {
  background: var(--widget-bg); color: var(--widget-text); font-family: var(--font-system);
  border-radius: 20px; padding: 14px 16px; box-shadow: var(--shadow-overlay);
  max-width: 100%; -webkit-font-smoothing: antialiased;
}
.wpv-card.list { width: 300px; }
.wpv-muted { color: var(--widget-muted); }
.wpv-up { color: var(--widget-up); }
.wpv-down { color: var(--widget-down); }
.wpv-rule { border-top: 1px solid var(--widget-line); margin: 8px 0; }
.wpv-head { display: flex; align-items: baseline; gap: 10px; }
.wpv-title { font-size: var(--fs-2xl); font-weight: 700; letter-spacing: -.01em; }
.wpv-place { font-size: var(--fs-base); font-weight: 500; color: var(--widget-muted); }
.wpv-price { display: flex; align-items: baseline; gap: 10px;
  font-size: var(--fs-xl); font-weight: 700; font-variant-numeric: tabular-nums; }
.wpv-period { font-size: var(--fs-base); font-weight: 500; color: var(--widget-muted); }
.wpv-src { font-size: var(--fs-xs); color: var(--widget-muted); margin-top: 2px; }
.wpv-svg { display: block; max-width: 100%; height: auto; margin-top: 10px; }
.wpv-grid { stroke: var(--widget-line); }
.wpv-base { stroke: var(--widget-muted); stroke-opacity: .5; }
.wpv-ytick { fill: var(--widget-text); font-size: var(--fs-2xs); font-weight: 500; }
.wpv-xtick { fill: var(--widget-muted); font-size: var(--fs-2xs); font-weight: 500; }
.wpv-line { fill: none; stroke-width: 2; stroke-linejoin: round; stroke-linecap: round; }
.wpv-line.up, .wpv-spark.up { stroke: var(--widget-up); }
.wpv-line.down, .wpv-spark.down { stroke: var(--widget-down); }
.wpv-line.flat, .wpv-spark.flat { stroke: var(--widget-muted); }
.wpv-stop.up { stop-color: var(--widget-up); }
.wpv-stop.down { stop-color: var(--widget-down); }
.wpv-stop.flat { stop-color: var(--widget-muted); }
.wpv-stats { display: flex; gap: 18px; margin-top: 8px; padding-top: 8px;
  border-top: 1px solid var(--widget-line); font-size: var(--fs-xs); }
.wpv-stats b { font-weight: 700; }
.wpv-row { display: flex; align-items: center; gap: 12px; padding: 8px 0; }
.wpv-row + .wpv-row { border-top: 1px solid var(--widget-line); }
.wpv-name { width: 104px; min-width: 0; }
.wpv-sym { font-size: var(--fs-md); font-weight: 700; white-space: nowrap; }
.wpv-port { font-size: var(--fs-xs); color: var(--widget-muted); white-space: nowrap;
  overflow: hidden; text-overflow: ellipsis; }
.wpv-spark { fill: none; stroke-width: 1.5; stroke-linejoin: round; stroke-linecap: round; }
.wpv-quote { margin-left: auto; text-align: right; }
.wpv-val { font-size: var(--fs-md); font-weight: 700; font-variant-numeric: tabular-nums; }
.wpv-pill { display: inline-block; margin-top: 2px; min-width: 58px; padding: 1px 6px;
  border-radius: 5px; font-size: var(--fs-xs); font-weight: 700; text-align: right;
  background: var(--widget-button); color: var(--widget-text); }
.wpv-pill.up { background: var(--widget-up); }
.wpv-pill.down { background: var(--widget-down); }
.wpv-clock { margin-top: 10px; padding-top: 10px; border-top: 1px solid var(--widget-line); }
.wpv-clock.alone { margin-top: 0; padding-top: 0; border-top: 0; min-width: 260px; }
.wpv-clock-row { display: flex; align-items: center; gap: 8px; }
.wpv-dot { width: 8px; height: 8px; border-radius: 50%; background: var(--widget-muted); }
.wpv-dot.in { background: var(--widget-down); }
.wpv-state { font-size: var(--fs-sm); font-weight: 700; }
.wpv-today { font-size: var(--fs-xs); color: var(--widget-muted); }
.wpv-spacer { flex: 1; }
.wpv-btn { font-family: inherit; font-size: var(--fs-xs); font-weight: 700; padding: 4px 11px;
  border-radius: 8px; border: 0; background: var(--widget-button); color: var(--widget-text); }
.wpv-btn.primary { background: var(--widget-blue); }
.wpv-warn { font-size: var(--fs-2xs); color: var(--widget-warn); margin-top: 6px; }
.wpv-note { font-size: var(--fs-xs); color: var(--widget-muted); margin: 10px 0; }
.wpv-foot { font-size: var(--fs-2xs); color: var(--widget-muted); margin-top: 8px; }
.btn.btn-compact {
  font-size: var(--fs-base); line-height: 1.5; padding: 6px 12px; border-width: 1px;
}
.btn-primary.btn-compact { border-color: var(--manora-blue); }
.btn-primary.btn-compact:hover { border-color: var(--manora-deep-navy); }
.btn-secondary.btn-compact {
  background: var(--manora-white); color: var(--manora-charcoal); border-color: var(--line);
}
.btn-secondary.btn-compact:hover {
  background: var(--manora-white); color: var(--manora-blue); border-color: var(--manora-blue);
}
.btn.btn-compact:disabled { border-color: var(--line); }

/* ------------------------------------------------ portal type
   Choice C1 C (UI overhaul 2026-09): the pages people work in — the
   dashboard, the account and the admin page, the placeholder — read at
   the app scale, as the record browsers do (the vessel library's
   main.browser): body and tables 14 px at 1.5, the page's h2 24 px blue,
   a card's h3 15 px navy with its dot and pill in one row, a tile's
   title 15 px, cards 24 × 28 px. The sign-in cards keep the 16 px scale
   above, which iPad Safari does not zoom into. Values only; switching
   back is deleting this block. */
main.page {
  font-size: var(--fs-base); line-height: var(--lh-body);
  padding-top: calc(var(--space-unit) * 3);
}
main.page h2 { font-size: var(--fs-2xl); }
main.page .page-head { margin-bottom: 20px; }
main.page .page-head h2 { margin: 0 0 4px; }
main.page .tool-grid + .page-head { margin-top: calc(var(--space-unit) * 5); }
main.page .card { padding: 24px 28px 26px; }
main.page .card h3 {
  font-size: var(--fs-md); color: var(--manora-deep-navy); margin: 0 0 12px;
  display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
}
main.page .card h3 .hint-dot { margin-left: 0; }
main.page .vf-subhead, main.page .card-subhead { font-size: var(--fs-base); margin: 20px 0 8px; }
main.page .small { font-size: var(--fs-sm); }
main.page .tool-card { padding: 20px; }
main.page .tool-card .icon { width: 40px; height: 40px; margin-bottom: 12px; }
main.page .tool-card .icon svg { width: 22px; height: 22px; }
main.page .tool-card h4 { font-size: var(--fs-md); margin-bottom: 4px; }
main.page .tool-card p { font-size: var(--fs-sm); }
main.page .tool-card .open { font-size: var(--fs-sm); }
main.page div.tool-card > .foot { padding-top: 14px; }
main.page .empty-state p { font-size: var(--fs-base); }

/* ---- moved up from manora_tool.css (UI overhaul 2026-09): the tool
   pages loaded these already; the portal pages now do too ---- */

/* ------------------------------------------------ verdicts + chips */
.chip {
  display: inline-block; padding: 3px 10px; border-radius: var(--radius-pill); margin: 2px 6px 2px 0;
  font-size: var(--fs-xs); background: var(--manora-mist);
}
.chip.PASS { background: var(--pass-bg); color: var(--pass); }
.chip.FAIL { background: var(--fail-bg); color: var(--fail); }
.chip.MIN { background: var(--amber-tint); color: var(--warn-text); }
.gov { background: var(--amber-tint); }

/* ------------------------------------------------ the switch
   ManoraUI.toggle (ui-standard §7.5): ONE on/off or yes/no, read as
   a switch — blue track = on, slate track = off, the knob slides.
   The real checkbox stays for the keyboard and the screen reader
   (role="switch"); the track is drawn on the span after it. */
.switch {
  display: inline-flex; align-items: center; gap: 8px;
  font-size: var(--fs-sm); cursor: pointer; position: relative;
  -webkit-user-select: none; user-select: none;
}
.switch input { position: absolute; opacity: 0; width: 0; height: 0; }
.switch .track {
  flex: none; width: 36px; height: 20px; border-radius: var(--radius-pill);
  background: var(--manora-slate); position: relative;
  transition: background .15s ease;
}
.switch .track::after {
  content: ""; position: absolute; top: 2px; left: 2px;
  width: 16px; height: 16px; border-radius: 50%;
  background: var(--manora-white);
  box-shadow: var(--shadow-knob);
  transition: transform .15s ease;
}
.switch input:checked + .track { background: var(--manora-blue); }
.switch input:checked + .track::after { transform: translateX(16px); }
.switch:hover .track { filter: brightness(.95); }
.switch input:focus-visible + .track {
  outline: 2px solid var(--manora-blue); outline-offset: 2px;
}
.switch input:disabled + .track { opacity: .45; cursor: default; }
.switch .nm { color: var(--manora-charcoal); }
.form-grid > .switch { justify-self: start; }

/* ------------------------------------------------ tick chips
   A SET of independent yes/no choices as one control
   (ManoraUI.chipSet) — the admin module picker's own chip too
   (.tick-chips.grid): same tick, same on-state, sized for a form row. One-of-N is a select, not a chip set. */
.tick-chips { display: flex; flex-wrap: wrap; gap: 8px; margin: 8px 0; }
/* inside a form grid the set takes the full row under its label —
   chips wrap side by side instead of stacking in the input column */
.form-grid > .tick-chips, .form-grid > .callout { grid-column: 1 / -1; }
.form-grid > .tick-chips { margin: 0 0 6px; }
.tick-chip {
  display: inline-flex; align-items: center; gap: 8px;
  padding: 5px 11px; font-size: var(--fs-sm);
  background: var(--manora-white);
  border: 1px solid var(--line); border-radius: var(--radius-sm);
  cursor: pointer;
  transition: border-color .15s ease, background .15s ease,
    box-shadow .15s ease;
}
.tick-chip:hover { border-color: var(--manora-sky); }
.tick-chip input { position: absolute; opacity: 0; width: 0; height: 0; }
.tick-chip .tick {
  flex: none; width: 15px; height: 15px; border-radius: var(--radius-sm);
  border: 1.5px solid var(--manora-slate); background: var(--manora-white);
  position: relative;
  transition: border-color .15s ease, background .15s ease;
}
.tick-chip.on {
  border-color: var(--manora-blue); background: var(--blue-tint-soft);
  box-shadow: inset 0 0 0 1px var(--blue-tint);
}
/* the chip follows its own checkbox too, before or without a script
   painting .on (the admin's module picker is a plain form underneath);
   :has() keeps a rule of its own, as a browser without it would drop
   a whole selector list */
.tick-chip:has(> input:checked) {
  border-color: var(--manora-blue); background: var(--blue-tint-soft);
  box-shadow: inset 0 0 0 1px var(--blue-tint);
}
.tick-chip.on .tick,
.tick-chip > input:checked + .tick {
  border-color: var(--manora-blue); background: var(--manora-blue);
}
.tick-chip.on .tick::after,
.tick-chip > input:checked + .tick::after {
  content: ""; position: absolute; left: 4px; top: 1px;
  width: 3.5px; height: 7px; border: solid var(--manora-white);
  border-width: 0 2px 2px 0; transform: rotate(42deg);
}
.tick-chip input:focus-visible + .tick {
  outline: 2px solid var(--manora-blue); outline-offset: 2px;
}
/* a chip that shows a state nobody may change here — you, on the
   list of who may open your own project */
.tick-chip.locked { cursor: default; opacity: .6; }
.tick-chip.locked:hover { border-color: var(--manora-blue); }

/* ------------------------------------------------ disclosure row
   ManoraUI.disclosure (ui-standard §10.3): the summary pill says
   whether you need to look (amber = something inside is not the
   default), the panel opens full width underneath. The admin page's rows
   are the same shape, server-rendered by _macros.html. */
.disc-row { margin: 8px 0 0; }
.disc-toggle {
  display: inline-flex; align-items: center; gap: 8px;
  padding: 5px 12px; font: inherit; font-size: var(--fs-sm);
  border: 1px solid var(--line); border-radius: var(--radius-pill);
  background: var(--manora-white); color: var(--manora-charcoal);
  cursor: pointer; white-space: nowrap;
  transition: border-color .15s ease, background .15s ease,
    color .15s ease;
}
.disc-toggle:hover { border-color: var(--manora-sky); }
.disc-toggle[aria-expanded="true"] {
  border-color: var(--manora-blue); color: var(--manora-blue);
}
.disc-toggle.warn {
  color: var(--warn-text); border-color: var(--amber-tint-strong);
}
.disc-toggle .chev { width: 14px; height: 14px;
  transition: transform .15s ease; }
.disc-toggle[aria-expanded="true"] .chev { transform: rotate(180deg); }
.disc-panel {
  margin: 8px 0; padding: 12px 14px 10px;
  background: var(--manora-white);
  border: 1px solid var(--line); border-left: 3px solid var(--manora-blue);
  border-radius: var(--radius);
}
.disc-panel .tick-chips { margin: 0; }

/* ------------------------------------------------ progress bar
   ManoraUI.progress: a wait with a bar that fills. The width moves
   every second (the bar counts on between polls), so the transition
   is linear and as long as a tick — it reads as a steady fill. */
.mprogress { margin: 8px 0 4px; }
.mprogress-bar { height: 6px; background: var(--manora-mist); border-radius: 3px; overflow: hidden; }
.mprogress-fill { height: 100%; width: 0; background: var(--manora-blue); border-radius: 3px;
  transition: width 1s linear; }
.mprogress-line { margin: 4px 0 0; font-variant-numeric: tabular-nums; }
/* on a panel's mist the track would vanish: it takes the hairline grey */
.disc-panel-row .mprogress-bar { background: var(--line); }

/* ------------------------------------------------ chart
   ManoraChart (manora_chart.js): a canvas the pointer reads. A finger
   scrolls the page up and down over it and scrubs sideways, so it is
   not a drawing surface's touch-action: none. */
.mchart { margin: 4px 0 0; }
.mchart canvas { display: block; width: 100%; cursor: crosshair; touch-action: pan-y;
  border: 0; border-radius: 0; background: transparent; }
.mchart-legend { display: flex; flex-wrap: wrap; align-items: center; gap: 6px 16px;
  margin: 2px 0 0; font-size: var(--fs-xs); color: var(--text-muted); }
.mchart-key { display: inline-flex; align-items: center; gap: 6px; }
.mchart-key i { display: inline-block; width: 18px; height: 10px; border-radius: 2px; }
.mchart-key i.line { height: 0; border-top: 2px solid currentColor; border-radius: 0; }
.mchart-key i.dash { height: 0; border-top: 2px dashed currentColor; border-radius: 0; }
.mchart-key i.band { opacity: .35; }
.mchart-legend .spacer { flex: 1; }

/* ------------------------------------------------ group toggle
   The chevron that opens a GROUP of rows — the sisters under a class
   in the Vessel Library's list and in the tools' vessel picker. Not
   the disclosure row (.disc-toggle above): that one hides a panel of
   detail behind a summary pill, this one hides rows behind their
   heading. One glyph either way (ManoraUI.chevron), rotated off
   [aria-expanded]. It lives here because two shared surfaces draw it;
   a header row that carries it sets its own background. */
.grp-toggle {
  flex: none; display: inline-flex; align-items: center;
  justify-content: center; width: 22px; height: 22px; padding: 0;
  border: 1px solid var(--line); border-radius: var(--radius-pill);
  background: var(--manora-white); color: var(--manora-blue);
  cursor: pointer;
  transition: border-color .15s ease, background .15s ease;
}
.grp-toggle:hover { border-color: var(--manora-sky); }
.grp-toggle .chev {
  width: 14px; height: 14px; transition: transform .15s ease;
}
.grp-toggle[aria-expanded="true"] .chev { transform: rotate(180deg); }

/* keyboard focus — matches the input focus ring above (inputs keep
   their own :focus rule; these cover buttons, links, tabs, cards) */
button:focus-visible, a:focus-visible, summary:focus-visible,
[tabindex]:focus-visible {
  outline: none;
  border-color: var(--manora-blue);
  box-shadow: var(--focus-ring);
}
.topbar-icon:focus-visible {
  border-color: var(--manora-sky);
  box-shadow: 0 0 0 3px var(--on-dark-focus);
}
.topbar a:focus-visible, .topbar button:focus-visible {
  box-shadow: 0 0 0 3px var(--on-dark-focus); border-radius: var(--radius-sm);
}

.error {
  background: var(--error-bg); border: 1px solid var(--error-border); color: var(--error-text);
  padding: 10px 12px; border-radius: var(--radius); margin: 10px 0; white-space: pre-wrap;
}
.callout {
  background: var(--amber-tint-soft); border: 1px solid var(--manora-amber);
  border-radius: var(--radius); padding: 8px 12px; margin: 8px 0; font-size: var(--fs-sm);
}

/* the numbers a page opens on */
.stat-grid {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(170px, 1fr));
  gap: 12px; margin-bottom: 12px;
}
.stat {
  padding: 10px 12px; border: 1px solid var(--line);
  border-radius: var(--radius); background: var(--manora-mist);
}
.stat-v {
  font-size: 17px; font-weight: 700; color: var(--manora-deep-navy);
  line-height: 1.3; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.stat-l {
  font-size: var(--fs-xs); color: var(--text-muted);
  text-transform: uppercase; letter-spacing: .04em;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
/* a third line under the label: WHEN the number is — the hour an
   extreme falls on, an as-of date. It exists so the label stays the
   quantity alone: a label carrying its date was the line that got
   cut in half (weather forecast, 9 Sep 2026). */
.stat-w {
  font-size: var(--fs-xs); color: var(--text-muted);
  margin-top: 3px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
/* .stat-grid.rows — the same tiles in a NARROW column (a tool page's
   sidebar): one per row, the label beside the value instead of under
   it, the when across the foot. Side by side in 170 px the value and
   the date are both ellipsised; one per row they fit, and the label
   on the right keeps the tile from being half empty. */
.stat-grid.rows { grid-template-columns: minmax(0, 1fr); gap: 8px; }
.stat-grid.rows .stat {
  display: grid; grid-template-columns: minmax(0, 1fr) auto;
  align-items: baseline; column-gap: 12px;
}
.stat-grid.rows .stat-l { text-align: right; }
.stat-grid.rows .stat-w { grid-column: 1 / -1; }

/* the row-lined table (table.list, manora.css) with what a tool
   table adds: a number column, a clickable row, a name with a sub-line */
table.list th.num, table.list td.num {
  text-align: right; font-variant-numeric: tabular-nums;
}

table.list tr.pick { cursor: pointer; }
table.list tr.pick:hover td { background: var(--manora-mist); }
/* a record's name: bold navy. A name INSIDE a cell stands on its own line
   (above its .sub); a cell that is itself .nm stays a table cell —
   display: block there took it out of the row, and its bottom line no
   longer met the row's (the Time Log's names, Haizea's MP ids) */
table.list .nm { font-weight: 700; color: var(--manora-deep-navy); }
table.list td .nm, table.list th .nm { display: block; }
table.list td.nm { white-space: nowrap; }
table.list .sub { display: block; font-size: 11.5px; color: var(--text-muted);
  font-weight: 400; }

/* a button that reads as a link */
button.linky, .link-btn {
  background: none; border: none; padding: 0; font-family: inherit;
  color: var(--manora-blue); cursor: pointer; text-align: left;
}
button.linky { font: inherit; }
button.linky:hover, .link-btn:hover { text-decoration: underline; color: var(--manora-blue); }

.spacer { flex: 1 1 8px; }

/* muted small text: a line under a control, the kit's progress line */
.hint { color: var(--text-muted); font-size: var(--fs-xs); }

/* ================================================================
   SHARED COMPONENTS (UI overhaul 2026-09). Class-based rules every
   page family uses — the portal pages as much as the tool pages — so
   they live here, after the portal skin; the tool skin
   (manora_tool.css) keeps only the tool BASE (body, headings, form
   controls, table.data, #topbar, #steps) and the tool-only kits.
   ================================================================ */

/* ------------------------------------------------ small and icon buttons
   One compact size for a button in a row, a caption or an export bar
   (button.sm), and one square for a glyph with an aria-label
   (button.icon). The portal's old .btn-small is gone: every small
   button, template or script, says button.sm / a.sm. */
button.sm, a.sm {
  display: inline-flex; align-items: center; justify-content: center; gap: 6px;
  font-family: var(--font-primary); font-size: var(--fs-sm); font-weight: 500;
  line-height: 1.3; padding: 3px 10px;
  border: 1px solid var(--line); border-radius: var(--radius);
  background: var(--manora-white); color: var(--manora-charcoal);
  cursor: pointer; white-space: nowrap;
  transition: background .15s ease, color .15s ease, border-color .15s ease;
}
button.sm:hover, a.sm:hover { border-color: var(--manora-blue); color: var(--manora-blue); background: var(--manora-white); }
/* a link dressed as a small button: a download beside the row's buttons */
a.sm { text-decoration: none; }
button.sm.primary { background: var(--manora-blue); border-color: var(--manora-blue); color: var(--manora-white); }
button.sm.primary:hover { background: var(--manora-deep-navy); border-color: var(--manora-deep-navy); color: var(--manora-white); }
button.sm.danger { color: var(--fail); border-color: var(--fail); }
button.sm.danger:hover { background: var(--fail); border-color: var(--fail); color: var(--manora-white); }
button.sm:disabled, button.sm:disabled:hover {
  opacity: .45; cursor: default; pointer-events: none;
  border-color: var(--line); color: var(--manora-charcoal); background: var(--manora-white);
}
/* keyboard focus: the ring (button:focus-visible) and a blue border, which
   the hairline of these buttons would otherwise keep */
button.sm:focus-visible, button.icon:focus-visible,
.disc-toggle:focus-visible { border-color: var(--manora-blue); }
button.icon {
  display: inline-flex; align-items: center; justify-content: center;
  width: 28px; height: 28px; padding: 0; line-height: 1;
  font-family: var(--font-primary); font-size: var(--fs-base);
  border: 1px solid var(--line); border-radius: var(--radius);
  background: var(--manora-white); color: var(--manora-charcoal); cursor: pointer;
}
button.icon:hover { border-color: var(--manora-blue); color: var(--manora-blue); }
button.icon.quiet { border-color: transparent; background: transparent; color: var(--text-muted); }
button.icon.quiet:hover { color: var(--fail); border-color: transparent; }

/* ------------------------------------------------ export bar + table copy
   ManoraExport (app/static/js/manora_export.js): "Copy · Download" at
   the right end of a block's header row for a chart, map, drawing or
   image; a "Copy" caption above every table (ManoraUI.dataTable and
   ManoraExport.tableCopy put it there). */
.export-bar { display: inline-flex; align-items: center; gap: 6px; flex-wrap: wrap; }
.export-bar .export-state { font-size: var(--fs-xs); color: var(--text-muted); }
.export-bar .export-state:empty { display: none; }
h3 .export-bar, h4 .export-bar, .row .export-bar { margin-left: auto; }
caption.tbl-tools {
  caption-side: top; text-align: right; padding: 0 0 4px;
  font-weight: 400; color: var(--text-muted);
}
caption.tbl-tools button { vertical-align: middle; }
/* a caption on a bordered table is outside the grid: no border */
table.data caption.tbl-tools { background: transparent; }

/* ------------------------------------------------ segmented control
   ManoraUI.segmented: one of N, side by side (a period, a view, a
   quantity). The pressed segment is blue; amber stays the colour of
   an ARMED tool (ui-overhaul choice C13). role="group" + aria-pressed. */
.seg { display: inline-flex; border: 1px solid var(--line); border-radius: var(--radius); overflow: hidden; background: var(--manora-white); }
.seg button, .seg button:hover {
  font-family: var(--font-primary); font-size: var(--fs-sm); font-weight: 500;
  padding: 4px 11px; border: 0; border-radius: 0; background: var(--manora-white);
  color: var(--manora-charcoal); cursor: pointer; white-space: nowrap;
}
.seg button + button { border-left: 1px solid var(--line); }
.seg button:hover { color: var(--manora-blue); }
.seg button.active, .seg button[aria-pressed="true"], .seg button.active:hover {
  background: var(--manora-blue); color: var(--manora-white);
}
.seg button:focus-visible { box-shadow: var(--focus-ring-inset); outline: none; }

/* ------------------------------------------------ selection, everywhere
   The one look for "this row / this point is selected" — the amber
   the editable tables use (table.data tr.selected, manora_tool.css). */
table.list tr.selected td { background: var(--amber-tint); }
.pt-row.selected { background: var(--amber-tint-soft); border-radius: var(--radius-sm); }
.list-row.selected { border-color: var(--manora-amber); background: var(--amber-tint-soft); }

/* ------------------------------------------------ disclosure, bare and in a table
   .disc-panel.bare draws no box (an "Advanced" fold of whole cards);
   tr.detail-row is the admin page's panel row (tr.disc-panel-row) for
   a table a script builds: ManoraUI.rowDetail. */
.disc-panel.bare { padding: 0; border: 0; background: none; margin: 8px 0 0; }
table.list tr.detail-row > td { padding: 0 0 16px; border-bottom: 1px solid var(--line); white-space: normal; }
.detail-panel {
  display: block; padding: 14px 16px 12px;
  background: var(--manora-mist);
  border: 1px solid var(--line); border-left: 3px solid var(--manora-blue);
  border-radius: var(--radius);
}
.detail-panel > h4:first-child { margin-top: 0; }

/* ------------------------------------------------ the Time Log's clock bar
   On the dashboard only, for a colleague who registers their time
   (timelog/web/clock.js). One slim row: a dot and the state, today's
   hours, the link to My hours, the buttons that fit now. The dot is
   blue while clocked in, slate when out. */
.tl-clock { margin: 0 0 calc(var(--space-unit) * 4); }
.tl-bar {
  display: flex; align-items: center; flex-wrap: wrap; gap: 10px 16px;
  padding: 10px 16px; min-height: 52px; box-sizing: border-box;
  background: var(--manora-white);
  border: 1px solid var(--line); border-radius: var(--radius);
  font-size: var(--fs-base);
}
.tl-bar .spacer { flex: 1; }
.tl-state { display: inline-flex; align-items: center; gap: 8px; font-weight: 500;
  color: var(--manora-deep-navy); }
.tl-dot { width: 10px; height: 10px; border-radius: 50%; background: var(--manora-slate); }
.tl-in .tl-dot { background: var(--manora-blue); }
.tl-today { color: var(--text-muted); }
.tl-link { font-size: var(--fs-sm); }
.tl-actions { display: inline-flex; gap: 8px; }
.tl-actions button.sm { padding: 6px 16px; font-size: var(--fs-base); }
.tl-gap, .tl-note {
  display: flex; align-items: center; flex-wrap: wrap; gap: 8px 12px;
  margin-top: 8px; padding: 8px 16px; font-size: var(--fs-sm);
  background: var(--manora-mist); border-radius: var(--radius);
}
.tl-gap-q { display: inline-flex; gap: 8px; align-items: center; color: var(--manora-charcoal); }
.tl-gap-chips { display: inline-flex; flex-wrap: wrap; gap: 6px; align-items: center; }
.tl-gap-chips input { font: inherit; padding: 4px 8px; width: 12em;
  border: 1px solid var(--line); border-radius: var(--radius-sm); }
.tl-note { background: var(--amber-tint-soft); color: var(--warn-text); }
.tl-note.tl-error { background: var(--error-bg); color: var(--error-text); }
.tl-gap-q .opt { font-size: var(--fs-xs); color: var(--text-muted); }

/* the Time Log's emailed confirm page (templates/timelog_confirm.html):
   the sign-in card, a little wider for the week's table */
.auth-card:has(.tl-confirm) { max-width: 520px; }
.tl-confirm-table { width: 100%; margin: 16px 0; font-size: var(--fs-base); }
.tl-confirm-table .sub { font-size: var(--fs-2xs); color: var(--text-muted); text-align: left; margin: 2px 0 0; }
.tl-confirm-table tr.tl-incomplete td { background: var(--amber-tint-soft); color: var(--warn-text); }
.tl-confirm .btn-block { margin-top: 12px; }
.tl-confirm-go { text-align: center; margin-top: 14px; font-size: var(--fs-sm); }
