/* ============================================================
   hdw-ui — BASE
   Reset, typography, and the polish that every hdw product gets
   for free. None of this needs a class. It just applies.
   ============================================================ */

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

/* `hidden` must always win. A component with `display:flex` beats the
   browser's own `[hidden]{display:none}`, which is how a modal ends up
   open on page load. Toggle visibility with el.hidden, not style.display. */
[hidden]{display:none !important;}

html{
  height:100%;
  background:var(--canvas);
  color:var(--fg);
  -webkit-text-size-adjust:100%;
  overscroll-behavior-y:none;      /* kills mobile pull-to-refresh eating a half-typed form */
  scroll-behavior:smooth;
}

body{
  min-height:100%;
  background:var(--canvas);
  color:var(--fg);
  font-family:var(--font-body);
  font-size:var(--fs-body);
  font-weight:400;
  line-height:var(--lh);
  /* crisper text on macOS — without this SF Pro renders heavy */
  -webkit-font-smoothing:antialiased;
  -moz-osx-font-smoothing:grayscale;
  overscroll-behavior-y:none;
  /* every number is tabular: a column of amounts lines up without a mono face */
  font-variant-numeric:tabular-nums;
}

::selection{background:var(--fg);color:var(--canvas);}
/* the browser makes these bold by default. Nothing in the app is bold. */
b,strong,th{font-weight:400;}

/* ---- NOTHING PUSHES A PHONE SIDEWAYS ----
   One pasted link, file name or handle can be wider than a phone
   screen, and it drags the whole layout left with it. `:where()`
   gives this zero specificity so it is only ever a default.
   `break-word` (not `anywhere`) breaks the offending word without
   changing any flex or grid track's min-content size. */
body :where(div,p,span,li,td,th,dd,dt,blockquote,figcaption,label,summary,h1,h2,h3,h4,h5,h6){
  overflow-wrap:break-word;
}

/* ---- TYPOGRAPHY DEFAULTS ---- */
h1,h2,h3,h4,h5,h6{
  font-family:var(--font-display);
  font-weight:400;                 /* hierarchy is size, never weight */
  line-height:var(--lh-snug);
  text-wrap:balance;               /* no lonely word on the last line */
}
h1{font-size:var(--fs-7);}
h2{font-size:var(--fs-6);}
h3{font-size:var(--fs-5);}
h4,h5,h6{font-size:var(--fs-4);}

/* big display text needs tighter line height and negative tracking,
   or it reads loose and amateur. Bare .hero is deliberately not here:
   hdwOS already uses .stat-num.hero for something else. */
.display,h1.display{
  font-size:var(--fs-10);
  line-height:var(--lh-tight);
  letter-spacing:var(--ls-tight);
}

p{text-wrap:pretty;}               /* no orphans in body copy */
p + p{margin-top:var(--s-3);}

.prose{max-width:var(--measure);line-height:var(--lh-prose);}
.prose p + p{margin-top:var(--s-4);}

a{color:inherit;text-decoration:none;}
a.link{
  color:var(--fg);
  text-decoration:underline;
  text-underline-offset:3px;
  text-decoration-thickness:1px;
  text-decoration-color:var(--border2);
  transition:text-decoration-color var(--dur-fast) var(--ease);
}
a.link:hover{text-decoration-color:var(--fg);}

small,.meta{font-size:var(--fs-meta);color:var(--fg2);}

/* ---- NUMBERS ----
   Any figure that changes gets tabular numerals, or the row jumps
   sideways every time the value updates. Mono for anything that
   should line up in a column: amounts, IDs, dates, counts. */
.num,.money,.stat-num,time,[data-num]{
  font-family:var(--font-mono);
  font-variant-numeric:tabular-nums;
  font-feature-settings:"tnum";
}
.tnum{font-variant-numeric:tabular-nums;}

/* ---- ALL-CAPS MONO LABEL — the only place tracking is widened ---- */
.label{
  font-family:var(--font-mono);
  font-size:var(--fs-label);
  letter-spacing:var(--ls-caps);
  text-transform:uppercase;
  color:var(--fg2);
  line-height:1;
}

/* ---- MEDIA ----
   A 1px outline gives every image a consistent edge. Pure black in
   light, pure white in dark. Never a tinted neutral — a tint picks
   up the surface underneath and reads as dirt on the image edge. */
img,svg,video,canvas{max-width:100%;height:auto;display:block;}
img{
  outline:1px solid rgba(0,0,0,.1);
  outline-offset:-1px;
}
:root[data-theme="dark"] img{outline-color:rgba(255,255,255,.1);}
@media (prefers-color-scheme: dark){
  :root:not([data-theme="light"]) img{outline-color:rgba(255,255,255,.1);}
}
img.plain{outline:none;}

/* ---- FOCUS ----
   Mouse users never see a ring. Keyboard users always do.
   Removing this without replacing it locks people out. */
:focus{outline:none;}
:focus-visible{
  outline:var(--focus-w) solid var(--focus);
  outline-offset:var(--focus-offset);
  border-radius:inherit;
}

/* ---- PRESS FEEDBACK ----
   Phones have no hover. Without a press state a tap feels dead.
   Press-down is near-instant, release animates back at normal speed.
   That asymmetry is what reads as responsive rather than laggy. */
a,button,[role="button"],label,summary,input,select,textarea{
  -webkit-tap-highlight-color:transparent;
}

/* ---- FORM ELEMENTS INHERIT THE SYSTEM ---- */
button,input,select,textarea{font:inherit;color:inherit;}
button{background:none;border:none;cursor:pointer;}
[disabled],.is-disabled{opacity:.4;cursor:not-allowed;pointer-events:none;}

/* ---- SCROLLBARS ---- */
::-webkit-scrollbar{width:4px;height:4px;}
::-webkit-scrollbar-track{background:transparent;}
::-webkit-scrollbar-thumb{background:var(--border2);border-radius:var(--r-pill);}
*{scrollbar-width:thin;scrollbar-color:var(--border2) transparent;}

/* ---- PAGE FRAME ---- */
.page{
  max-width:var(--page-max);
  margin:0 auto;
  padding:var(--page-pad-y) var(--page-pad-x);
  display:flex;flex-direction:column;gap:var(--page-gap);
}
.stack{display:flex;flex-direction:column;gap:var(--s-3);}
.row{display:flex;align-items:center;gap:var(--s-2);}
.row-between{display:flex;align-items:center;justify-content:space-between;gap:var(--s-3);}
.spacer{flex:1;}

/* ---- UTILITIES (a short list on purpose) ---- */
.muted{color:var(--fg2);}
.faint{color:var(--fg3);}
.accent{color:var(--orange);}
.center{text-align:center;}
.nowrap{white-space:nowrap;}
.truncate{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;min-width:0;}
.clamp-2{display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden;}
.hidden{display:none !important;}
.sr-only{
  position:absolute;width:1px;height:1px;padding:0;margin:-1px;
  overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap;border:0;
}

/* ---- ENTER ANIMATIONS ----
   Split content into chunks and stagger them. One well-orchestrated
   page load beats a dozen scattered micro-interactions. */
@keyframes hdwFadeUp{
  from{opacity:0;transform:translateY(8px);}
  to{opacity:1;transform:none;}
}
@keyframes hdwFade{from{opacity:0;} to{opacity:1;}}
@keyframes hdwPop{
  from{opacity:0;transform:scale(.96);}
  to{opacity:1;transform:none;}
}

.enter{animation:hdwFadeUp var(--dur-slow) var(--ease-out) both;}
.enter-fade{animation:hdwFade var(--dur-slow) var(--ease-out) both;}
/* put .stagger on a parent — its children reveal one after another */
.stagger > *{animation:hdwFadeUp var(--dur-slow) var(--ease-out) both;}
.stagger > *:nth-child(1){animation-delay:0ms;}
.stagger > *:nth-child(2){animation-delay:calc(var(--stagger) * 1);}
.stagger > *:nth-child(3){animation-delay:calc(var(--stagger) * 2);}
.stagger > *:nth-child(4){animation-delay:calc(var(--stagger) * 3);}
.stagger > *:nth-child(5){animation-delay:calc(var(--stagger) * 4);}
.stagger > *:nth-child(6){animation-delay:calc(var(--stagger) * 5);}
.stagger > *:nth-child(7){animation-delay:calc(var(--stagger) * 6);}
.stagger > *:nth-child(8){animation-delay:calc(var(--stagger) * 7);}
.stagger > *:nth-child(n+9){animation-delay:calc(var(--stagger) * 8);}

/* ---- REDUCED MOTION ----
   Not optional. Some people get physically ill from motion.
   Everything still works, it just arrives instead of moving. */
@media (prefers-reduced-motion: reduce){
  *,*::before,*::after{
    animation-duration:.01ms !important;
    animation-iteration-count:1 !important;
    transition-duration:.01ms !important;
    scroll-behavior:auto !important;
  }
}

/* ---- PRINT ---- */
@media print{
  :root{--canvas:#fff;--bg:#fff;--fg:#000;--fg2:#444;--border:rgba(0,0,0,.2);}
  body{background:#fff;color:#000;}
  .no-print{display:none !important;}
}

/* ============================================================
   hdwOS BASE — kept verbatim from the app it was proven in.
   These come last on purpose, so where the two disagree the
   value 43 live pages already use is the one that wins.
   ============================================================ */
/* 2 — RESET / BASE */
*,*::before,*::after{box-sizing:border-box;margin:0;padding:0;}
html{height:100%;background:var(--canvas);color:var(--fg);overscroll-behavior-y:none;}
::selection{background:#ff2e00;color:#fff;}
/* kill the mobile browser's native pull-to-refresh — it was reloading the page
   (and wiping a half-typed new task) whenever you scrolled a form at scroll-top */
body{min-height:100%;background:var(--canvas);color:var(--fg);font-family:var(--font-body);font-weight:400;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;font-size:var(--fs-body);overscroll-behavior-y:none;}
/* NOTHING PUSHES A PHONE SIDEWAYS (2026-08-15).
   A pasted Drive link in a task's "Changes requested" note was 129px wider
   than an iPhone screen, and because it sat inside the record overlay — one
   scroll box — the WHOLE screen slid left: the title, the property labels
   and every field label were cut off at the edge. Measured, not guessed:
   the overlay's scrollWidth read 515 against a 386 viewport.
   One unbreakable word did that, and any pasted link, file name or long
   handle can do it again on any page.
   `:where()` gives this ZERO specificity, so it is only ever a default and
   any real rule still wins. `break-word` (not `anywhere`) is deliberate: it
   breaks a word that would otherwise overflow WITHOUT shrinking the
   element's min-content size, so no flex or grid track changes shape. */
body :where(div,p,span,li,td,th,dd,dt,blockquote,figcaption,label,summary,h1,h2,h3,h4,h5,h6){overflow-wrap:break-word;}
/* ---------- interface-feel polish (make-interfaces-feel-better) ---------- */
/* tabular numbers: dynamic figures never cause layout shift */
.money,.stat-num,.r-mbig,.sc-date,.cz-count,.nf-time,.stat-label,.kv .money,.retainer,.tm-sal .v{font-variant-numeric:tabular-nums;}
/* scale on press — tactile feedback (0.96 exactly; never below 0.95). transitions stay specific. */
.btn,.chip,.tab,.vtab,.spill,.btn-icon,.pbtn{transition-property:background,color,border-color,opacity,transform,box-shadow;transition-duration:var(--dur);transition-timing-function:var(--ease);}
/* ---- tap feedback: every press answers back ----
   Phones have no hover, so without this a tap feels dead. The press-down is near-instant
   (.05s) while the release animates back at the normal duration — that asymmetry is what
   makes it feel responsive rather than laggy. The default gray tap-flash is killed since
   these states replace it. */
a,button,[onclick],[role="button"],label,summary{-webkit-tap-highlight-color:transparent;}
.btn:active,.chip:active,.tab:active,.vtab:active,.spill:active,.btn-icon:active,.pbtn:active{transform:scale(.965);transition-duration:.05s;}
.nav-item:active,.nav-subitem:active,.row-item:active,.nav-brandgo:active{background:var(--bg3);}
.nav-brandcv:active{opacity:1;background:var(--bg3);}
.btn:active,.chip:active,.tab:active,.vtab:active,.spill:active,.btn-icon:active,.pbtn:active{transform:scale(.96);}
/* balanced headings + tidy body wrapping (no orphans) */
h1,h2,h3,.greeting,.deck-title,.deck-brand,.pv-brand,.r-brand,.page-title,.modal-title,.empty-title{text-wrap:balance;}
.greeting-sub,.empty-sub,.cap,.di-cap,.field-hint,.pv-sub{text-wrap:pretty;}
/* subtle image outline for consistent edge depth (pure black/white per theme, never tinted) */
.ig-tile img,.di-thumb img,.pv-tile img,.side-thumb img,.fcal-th{outline:1px solid rgba(0,0,0,.1);outline-offset:-1px;}
[data-theme="dark"] .ig-tile img,[data-theme="dark"] .di-thumb img,[data-theme="dark"] .pv-tile img,[data-theme="dark"] .side-thumb img,[data-theme="dark"] .fcal-th{outline-color:rgba(255,255,255,.1);}
::-webkit-scrollbar{width:4px;height:4px;}
::-webkit-scrollbar-track{background:transparent;}
::-webkit-scrollbar-thumb{background:var(--border2);}
/* privacy: amounts masked to ₹#*@%$& by JS until the founder reveals them */
[data-privacy="on"] .money{user-select:none;letter-spacing:0;cursor:pointer;}

/* 3 — THEME HOOKS */
/* dark: native date/clock picker icon is black-on-dark — invert so it's tappable */
[data-theme="dark"] input[type="date"]::-webkit-calendar-picker-indicator,[data-theme="dark"] input[type="time"]::-webkit-calendar-picker-indicator{filter:invert(1);opacity:.65;cursor:pointer;}
[data-theme="dark"] input[type="date"]::-webkit-calendar-picker-indicator:hover,[data-theme="dark"] input[type="time"]::-webkit-calendar-picker-indicator:hover{opacity:1;}

