/* ITZA Diary - design system.
 *
 * A writing environment for people who take their own writing seriously. It
 * must feel like a diary, not a dashboard, and not like a crypto product. A
 * person who does not know what a blockchain is must never meet one.
 *
 * NO WEB FONTS. cdn.itzalabs.com is the only permitted remote origin, and
 * that is for the platform library alone - no font CDN, no icon font, no
 * external stylesheet. These stacks use what is already on the device, which
 * costs nothing and never blocks first paint.
 */

:root {
  /* Spec 17.2. Two values are deliberately darker than the source palette -
   * see the note below - and everything else is verbatim. */
  --ink: #12161c;      /* body text, dominant by area */
  --paper: #fbfaf7;    /* the reading surface */
  --navy: #0b2a4a;     /* headers, structure */
  --gold: #f5c711;     /* THE SINGLE ACCENT: verification, provenance only */
  --rule: #e2ded6;     /* hairlines */

  /* CONTRAST CORRECTIONS, against --paper, per the 17.5 quality floor
   * ("WCAG 2.1 AA contrast verified against the reading surface
   * specifically"). The source values fail that floor for body-size text:
   *
   *   --muted #6b7280 -> 4.26:1   below the 4.5:1 minimum
   *   --blue  #0c7ffb -> 3.70:1   below the 4.5:1 minimum
   *
   * Metadata and links are both normal-size text on the reading surface, so
   * both need 4.5:1. The corrected values below measure 5.0:1 and are within
   * a hair of the originals in hue. The original --blue is kept as
   * --blue-bright for large UI elements and focus rings, where 3:1 is the
   * applicable threshold and it passes comfortably. */
  --muted: #666d79;        /* metadata, timestamps - 5.0:1 */
  --blue: #0b6ad4;         /* interactive, links, actions - 5.0:1 */
  --blue-bright: #0c7ffb;  /* large UI and focus only, never body text */

  /* 42rem at the 20px body is ~65 characters a line - the classic reading
   * measure, and within a few pixels of Medium's 680px column. The first
   * version shipped 34rem (~50 chars): correct for a printed novella,
   * visibly cramped for a web article (user comparison, 2026-08-05). The
   * measure is in rem on purpose: the text-size setting scales the root, so
   * characters-per-line stays constant at every size. */
  --measure: 42rem;        /* reader-adjustable, see 17.3 */
  --body-size: 20px;       /* reader-adjustable, 19-21px range */
  --leading: 1.65;

  --serif-body: 'Iowan Old Style', 'Palatino Linotype', Palatino, Charter,
    'Bitstream Charter', 'Source Serif Pro', serif;
  --serif-display: 'Hoefler Text', 'Baskerville Old Face', Baskerville,
    'Times New Roman', serif;
  --sans: system-ui, -apple-system, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif;
}

/* Reader controls (17.3): the reading experience is the product, so the
 * reader sets the scale and the line width. Applied on <html> by an inline
 * script BEFORE first paint, so articles inherit them without JavaScript and
 * without a flash at the wrong size. */
/* The type scale moves the ROOT SIZE as well as the article body. The first
 * version scaled only --body-size, so dates, bylines, menus and every other
 * rem-sized surface ignored the reader's setting entirely (reported
 * 2026-08-02: "it doesn't seem to be affecting the date and other areas").
 * rem inherits from here, so now everything breathes together. */
html[data-size='s'] { --body-size: 19px; font-size: 15px; }
html[data-size='l'] { --body-size: 21px; font-size: 17.5px; }
html[data-size='xl'] { --body-size: 23px; font-size: 19px; }
/* Narrow IS the old default - anyone who liked the tighter column picks it
 * in Settings and gets exactly what shipped before. */
html[data-measure='narrow'] { --measure: 34rem; }
html[data-measure='wide'] { --measure: 48rem; }
html[data-justify='1'] .article p { text-align: justify; hyphens: auto; }

/* Reading surface themes. Dark keeps the same hierarchy rather than inverting
 * it, and gold stays gold because it means one thing in both (17.2). Each is
 * checked for AA contrast against its own paper, not against the light one. */
html[data-theme='dark'] {
  --ink: #e8e6e1;
  --paper: #14171c;
  --navy: #a9c6e8;
  --rule: #2b3038;
  --muted: #9aa1ad;       /* 7.0:1 on this paper */
  --blue: #6fb3ff;        /* 6.9:1 */
  --blue-bright: #8ec6ff;
}

html[data-theme='hc'] {
  --ink: #000000;
  --paper: #ffffff;
  --navy: #000000;
  --rule: #000000;
  --muted: #3a3a3a;
  --blue: #0033cc;
  --gold: #a06f00;        /* the mark still reads at high contrast */
}

/* A reader who asked for less motion gets it whether or not the OS knows. */
html[data-motion='reduce'] *,
html[data-motion='reduce'] *::before,
html[data-motion='reduce'] *::after {
  animation-duration: 0.001ms !important;
  transition-duration: 0.001ms !important;
}

/* ---------------------------------------------------------------------
   Screens, modal, toast
   --------------------------------------------------------------------- */

.screen { display: none; }
.screen.on { display: block; }
.screen:focus { outline: none; }

.apphead {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  padding: 0.7rem 1.25rem;
  border-bottom: 1px solid var(--rule);
  font-family: var(--sans);
}

/* The wordmark - the HOUSE STANDARD, mirrored from the marketing site's
 * stylesheet: ITZA in corporate blue (600) runs straight into the product
 * word in gold (800), no space. On light paper the gold deepens to #ad8009
 * to clear the contrast floor (brand gold on near-white is illegible - the
 * site's own comment); on dark it brightens back to brand gold, and ITZA
 * lifts to the site's dark-context blue. */
.brand {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  font-family: var(--serif-display);
  font-size: 1.05rem;
  text-decoration: none;
  letter-spacing: -0.01em;
}

.brand-mark { width: 22px; height: 22px; }
.wm { white-space: nowrap; }
.wm-itza { color: #0c7ffb; font-weight: 600; }
.wm-prod { color: #ad8009; font-weight: 800; }
html[data-theme='dark'] .wm-itza { color: #4d9bff; }
html[data-theme='dark'] .wm-prod { color: #f5c711; }

.appnav { display: flex; align-items: center; gap: 1rem; font-size: 0.82rem; }
.appnav a { color: var(--blue); text-decoration: none; padding-bottom: 2px; }
.appnav a:hover { text-decoration: underline; }
.appnav a[aria-current='page'] { color: var(--navy); font-weight: 600; border-bottom: 2px solid var(--navy); }
.appnav a[hidden] { display: none; }

/* Visible keyboard focus everywhere (17.5). */
/* Focus, in two registers.
 *
 * CONTROLS - things you press - keep a visible ring: keyboard users navigate
 * by it, and 3:1 contrast against any surface is the requirement the bright
 * blue exists to meet.
 *
 * FIELDS - things you type into - show focus with the caret they already
 * have, plus a quiet border shift. A ring around a text field says "form";
 * around the writing surface it says "you are filling in a box" on the exact
 * pixels where the design is supposed to say "you are writing the page". */
a:focus-visible, button:focus-visible, select:focus-visible,
[role="button"]:focus-visible {
  outline: 2px solid var(--blue-bright);
  outline-offset: 2px;
}

input:focus-visible, textarea:focus-visible {
  outline: none;
  border-color: var(--blue);
  box-shadow: 0 0 0 3px rgba(12, 127, 251, 0.13);
}

/* The writing surface itself: no ring, no glow, no box. The caret, the
 * placeholder disappearing and the toolbar arriving are the focus state.
 * This is also what keeps the editor visually identical to the published
 * page - same measure, same type, no furniture around it. */
.editor:focus-visible,
.editor:focus,
.title-input:focus-visible {
  outline: none;
  border-color: transparent;
  box-shadow: none;
}

.iconbtn {
  background: transparent;
  border: 1px solid var(--rule);
  color: var(--muted);
  border-radius: 4px;
  font-size: 1rem;
  line-height: 1;
  padding: 0.3rem 0.5rem;
  cursor: pointer;
}

#scrim {
  display: none;
  position: fixed;
  inset: 0;
  background: rgba(11, 42, 74, 0.45);
  /* ABOVE #screen-onboard.on (z 50, ported verbatim from Chess). At 40 the
   * signup confirmation modal opened UNDERNEATH the opaque sign-in card:
   * "Create account" appeared to do absolutely nothing, while its modal sat
   * waiting where no click could reach it. Chess's own scrim is 60 for the
   * same reason - the modal layer must beat every screen, onboarding
   * included. */
  z-index: 60;
  padding: 1rem;
  overflow-y: auto;
}

#scrim.on { display: flex; align-items: flex-start; justify-content: center; }

#modal {
  background: var(--paper);
  color: var(--ink);
  border: 1px solid var(--rule);
  border-radius: 8px;
  width: 100%;
  max-width: 32rem;
  margin: 3vh auto;
  padding: 1.25rem;
  font-family: var(--sans);
  font-size: 0.88rem;
}

.mhead {
  font-family: var(--serif-display);
  font-size: 1.4rem;
  color: var(--navy);
  margin-bottom: 1rem;
}

.mbtns { margin-top: 1.25rem; }

#toast {
  position: fixed;
  left: 50%;
  bottom: 1.5rem;
  transform: translateX(-50%) translateY(1rem);
  background: var(--navy);
  color: var(--paper);
  font-family: var(--sans);
  font-size: 0.82rem;
  line-height: 1.4;
  padding: 0.7rem 1rem;
  border-radius: 6px;
  max-width: min(34rem, calc(100vw - 2rem));
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.18s ease, transform 0.18s ease;
  /* Above every screen AND the modal scrim (60) - a toast is feedback about
   * the thing you just did and must never be buried under it. Chess puts its
   * toasts at 90 for the same reason. At 50 this TIED #screen-onboard.on and
   * only won by DOM order, which is a coin toss nobody should bet UI on. */
  z-index: 90;
}

#toast.on { opacity: 1; transform: translateX(-50%) translateY(0); }

/* ---------------------------------------------------------------------
   Sign in - PORTED 1:1 FROM ITZA CHESS, which ported it from ITZA CHAT
   ---------------------------------------------------------------------

   These values are Chess's, verbatim, not a reinterpretation of them. The
   sign-in screen is the same screen in every ITZA app on purpose: it is the
   same account, and a person who has signed in to one should recognise the
   next one immediately.

   SELF-CONTAINED. The whole palette is scoped to #screen-onboard rather than
   :root, so the card cannot be disturbed by the app's own theme and cannot
   disturb it either. Light is the default; dark follows the app's theme
   attribute, which here is html[data-theme] rather than Chess's
   html[data-bg] - that mapping is the only change made to any of it.
   --------------------------------------------------------------------- */

#screen-onboard{
  --ob-blue:#0c7ffb; --ob-blue-soft:#1d6fd0; --ob-gold:#f5c711;
  --ob-acc:#0c7ffb; --ob-acc-ink:#ffffff;
  --ob-bg:#f3f4f6; --ob-bg2:#ffffff; --ob-bg3:#f7f7f8;
  --ob-ink:#0b2a4a; --ob-ink2:#1e416b; --ob-ink3:#41618c;
  --ob-line:#d7dbe2; --ob-line2:#c5ccd6; --ob-hover:rgba(12,127,251,.06);
  --ob-card-shadow:0 18px 50px rgba(24,59,103,.12);
  --ob-mono:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;
  --ob-r-sm:8px;
  --ob-danger:#c62828;
}
html[data-theme="dark"] #screen-onboard{
  --ob-bg:#0b1f3a; --ob-bg2:#10294a; --ob-bg3:#173058;
  --ob-ink:#e8edf4; --ob-ink2:#9db0c7; --ob-ink3:#5b7089;
  --ob-line:#1e3a63; --ob-line2:#28466f; --ob-hover:rgba(255,255,255,.05);
  --ob-card-shadow:0 18px 50px rgba(0,0,0,.45);
}
#screen-onboard{padding:0}
#screen-onboard.on{
  position:fixed; inset:0; z-index:50; display:flex; align-items:center; justify-content:center;
  padding:16px; overflow-y:auto;
  background:linear-gradient(to bottom,#ffffff 0,#ffffff 200px,var(--ob-blue) 200px,var(--ob-blue) 224px,var(--ob-bg) 224px);
}
html[data-theme="dark"] #screen-onboard.on{
  background:linear-gradient(to bottom,#10294a 0,#10294a 200px,var(--ob-blue) 200px,var(--ob-blue) 224px,var(--ob-bg) 224px);
}
#screen-onboard .obcard{
  width:100%; max-width:430px; margin:0; text-align:left;
  background:var(--ob-bg2); border:1px solid var(--ob-line); border-radius:22px;
  padding:22px; box-shadow:var(--ob-card-shadow); color:var(--ob-ink);
  font:13px/1.45 -apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Helvetica,Arial,sans-serif;
}
#screen-onboard .hd{display:flex; align-items:center; gap:10px; margin-bottom:4px}
#screen-onboard .pyr{width:44px; height:auto}
#screen-onboard h1{font-size:19px; letter-spacing:.01em; font-weight:700; margin:0; font-family:inherit; color:var(--ob-ink)}
#screen-onboard .tag{font-size:11.5px; color:var(--ob-ink2); margin-bottom:14px}
#screen-onboard .tag b{color:#8d6f00}
html[data-theme="dark"] #screen-onboard .tag b{color:var(--ob-gold)}
#screen-onboard .pill{font-size:9.5px; padding:1px 7px; border-radius:99px; border:1px solid var(--ob-line2); color:var(--ob-ink3); text-transform:uppercase; letter-spacing:.05em; font-weight:400}
#screen-onboard label{display:block; margin:12px 0 4px; font-size:11.5px; color:var(--ob-ink2); font-weight:600; text-align:left}
#screen-onboard label .lbl2{color:var(--ob-ink3); font-weight:400}
#screen-onboard input,#screen-onboard textarea{
  width:100%; font:inherit; color:var(--ob-ink); background:var(--ob-bg3);
  border:1px solid var(--ob-line2); border-radius:var(--ob-r-sm); padding:6px 9px; outline:none;
}
#screen-onboard input:focus,#screen-onboard textarea:focus{border-color:var(--ob-acc)}
#screen-onboard ::placeholder{color:var(--ob-ink3)}
#screen-onboard .obtoggle{display:flex; gap:4px; margin-bottom:12px}
#screen-onboard .obtoggle button{flex:1; font-size:11.5px; padding:6px; border-radius:var(--ob-r-sm); border:1px solid var(--ob-line2); color:var(--ob-ink2); background:none; cursor:pointer}
#screen-onboard .obtoggle button.on{border-color:var(--ob-acc); color:var(--ob-ink); background:var(--ob-hover); font-weight:700}
#screen-onboard .row2{display:flex; gap:8px}
#screen-onboard .row2 .btn,#screen-onboard .row2 input{flex:1; min-width:0}
#screen-onboard .btn{
  background:linear-gradient(135deg,var(--ob-acc),var(--ob-blue-soft)); color:var(--ob-acc-ink);
  font-weight:700; font-size:12.5px; padding:8px 16px; border-radius:10px; border:none; cursor:pointer;
  box-shadow:0 8px 18px rgba(12,127,251,.22);
}
#screen-onboard .btn:disabled{opacity:.45; cursor:default; box-shadow:none}
#screen-onboard .btn.ghost{background:var(--ob-bg3); color:var(--ob-ink); border:1px solid var(--ob-line2); font-weight:600; box-shadow:none}
#screen-onboard .btn.gold{background:var(--ob-gold); color:#231c00; box-shadow:none}
#screen-onboard .btn.wide{width:100%}
#screen-onboard .feenote{font-size:10px; color:var(--ob-ink3); text-align:left; margin-top:0}
#screen-onboard .feenote b{color:var(--ob-ink2)}
#screen-onboard .linklike{display:block; margin:14px auto 0; background:none; border:none; color:var(--ob-blue); font-size:12px; cursor:pointer; text-decoration:underline; text-underline-offset:3px}
#screen-onboard .qrframe{display:flex; justify-content:center; margin:6px 0 2px}
#screen-onboard #obQrBox{width:190px; height:190px; border-radius:12px; background:#fff; border:1px solid var(--ob-line); display:flex; align-items:center; justify-content:center; position:relative}
#screen-onboard #obQrBox .qrph{font-family:var(--ob-mono); font-size:34px; color:var(--ob-line2); letter-spacing:2px}
#screen-onboard #obQrBox svg{width:100%; height:100%; display:block; border-radius:10px}
#screen-onboard .keybox{font-family:var(--ob-mono); font-size:10.5px; background:var(--ob-bg3); border:1px dashed var(--ob-line2); border-radius:var(--ob-r-sm); padding:8px; word-break:break-all; user-select:all; color:var(--ob-ink)}
#screen-onboard .savekey{display:flex; gap:8px; align-items:flex-start; margin-top:9px; font-size:11.5px; color:var(--ob-ink2)}
#screen-onboard .savekey input{width:auto; margin-top:2px}
#screen-onboard .settingsec{border-top:1px solid var(--ob-line); margin-top:12px; padding-top:10px}
#screen-onboard .settingsec h4{font-size:11px; text-transform:uppercase; letter-spacing:.07em; color:var(--ob-ink3); margin-bottom:6px}
#screen-onboard .spinner{display:inline-block; width:13px; height:13px; border:2px solid var(--ob-line2); border-top-color:var(--ob-blue); border-radius:50%; animation:spin .8s linear infinite; vertical-align:-2px; margin-right:4px}
@keyframes spin{to{transform:rotate(360deg)}}

/* The two ways in. Both buttons full width so neither reads as the "small"
   option; the Vault one is ghost so the lead is unambiguous. */
#screen-onboard #obChoose{ display:flex; flex-direction:column; gap:10px; margin:16px 0 4px; }
#screen-onboard #obChoose .btn{ height:46px; font-size:15px; font-weight:700; }
#screen-onboard #obBack{ margin-top:0; margin-bottom:10px; display:inline-block; }

/* ---- password fields: show/hide, and problems stated in place ----
   The eye sits INSIDE the field's box (the input reserves room for it via
   padding-right) so it never reflows the form when it appears. */
.pwwrap{ position:relative; display:block; }
.pwwrap input{ width:100%; padding-right:44px; }
.pweye{
  position:absolute; top:50%; right:6px; transform:translateY(-50%);
  width:32px; height:32px; display:flex; align-items:center; justify-content:center;
  border-radius:8px; color:var(--ob-ink3); cursor:pointer; padding:0;
  background:none; border:none;
}
#screen-onboard .pweye:hover{ color:var(--ob-ink); background:var(--ob-hover); }
.pweye svg{ width:20px; height:20px; display:block; }
.pweye.on{ color:var(--ob-acc); }
/* In Arabic and Hebrew the text starts on the RIGHT, so an eye pinned to the
   right sits on top of it. Mirror the whole arrangement, padding included.
   The onboarding card restyles its inputs behind an ID, which outranks a
   plain class rule - so the room for the eye has to be reserved at the same
   specificity, in both directions. */
html[dir="rtl"] .pwwrap input{ padding-right:12px; padding-left:44px; }
html[dir="rtl"] .pweye{ right:auto; left:6px; }
#screen-onboard .pwwrap input{ padding-right:44px; }
html[dir="rtl"] #screen-onboard .pwwrap input{ padding-right:9px; padding-left:44px; }

/* A mismatch is a STOP, not a whisper: red text under the field, both boxes
   outlined, stated the moment it is true rather than only on submit. */
.fieldErr{
  margin-top:8px; padding:9px 12px; border-radius:9px;
  border:2px solid #c62828; color:#c62828;
  font-size:13.5px; font-weight:700; line-height:1.4;
}
#screen-onboard .fieldErr{ color:#c62828; border-color:#c62828; background:rgba(198,40,40,.07); }
html[data-theme="hc"] #screen-onboard .fieldErr{ color:#8c0000; border-color:#8c0000; background:rgba(140,0,0,.10); }
input.err, .pwwrap input.err{ border-color:#c62828; box-shadow:0 0 0 3px rgba(224,40,40,.18); }
#screen-onboard input.err{ border-color:#c62828; box-shadow:0 0 0 3px rgba(198,40,40,.16); }

/* The account warning, repeated at the moment of no return. Bigger than the
   inline note by design - this is the last point where a forgotten password
   is still fixable. */
.obWarnBig{
  border:2px solid #c62828; border-radius:12px;
  padding:14px 16px; margin:4px 0 6px; font-size:15px; line-height:1.55;
}
.obWarnBig b.lead{ display:block; font-size:16px; margin-bottom:8px; }
.obWarnBig .hl{
  font-weight:800; background:rgba(245,199,17,.24);
  padding:1px 5px; border-radius:5px;
}

/* ---------------------------------------------------------------------
   Settings
   --------------------------------------------------------------------- */

.profBlock { border: 1px solid var(--rule); border-radius: 6px; padding: 0.9rem 1rem; margin-bottom: 1rem; }
.profName { font-family: var(--serif-display); font-size: 1.15rem; color: var(--navy); }

.modeRow { display: flex; gap: 0.3rem; margin-bottom: 1rem; }
.modebtn {
  flex: 1;
  background: transparent;
  color: var(--muted);
  border: 1px solid var(--rule);
  border-radius: 4px;
  padding: 0.4rem 0.3rem;
  font-size: 0.78rem;
  cursor: pointer;
}
.modebtn.on { color: var(--paper); background: var(--navy); border-color: var(--navy); }

.setPane { display: none; }
.setPane.on { display: block; }

.setRow {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  padding: 0.6rem 0;
  border-bottom: 1px solid var(--rule);
}

.setRow > span:first-child { flex: 1; }

.setRow select {
  font-family: var(--sans);
  font-size: 0.82rem;
  padding: 0.3rem 0.4rem;
  border: 1px solid var(--rule);
  border-radius: 4px;
  background: transparent;
  color: var(--ink);
}

.setRow input[type='checkbox'] { width: 1.1rem; height: 1.1rem; flex: none; }

.setNote {
  font-size: 0.74rem;
  color: var(--muted);
  line-height: 1.5;
  margin: 0.4rem 0 0.8rem;
}

.verVal { font-size: 0.76rem; color: var(--muted); font-variant-numeric: tabular-nums; }
.acctNote { font-size: 0.8rem; color: var(--muted); margin-bottom: 0.8rem; }

* { box-sizing: border-box; }

html, body {
  margin: 0;
  padding: 0;
  background: var(--paper);
  color: var(--ink);
}

body {
  font-family: var(--serif-body);
  font-size: var(--body-size);
  line-height: var(--leading);
  -webkit-text-size-adjust: 100%;
}

/* ---------------------------------------------------------------------
   The reading surface
   --------------------------------------------------------------------- */

/* Spec 17.5: articles render WITHOUT JavaScript. They are documents served
 * from nodes, and progressive enhancement is the right posture for a platform
 * whose whole claim is durability. Nothing in this block depends on script. */
.article {
  max-width: var(--measure);
  margin: 0 auto;
  padding: 3rem 1.25rem 6rem;
}

.article h1 {
  font-family: var(--serif-display);
  font-size: 2.4em;
  line-height: 1.12;
  letter-spacing: -0.02em;   /* 17.3: tight tracking at large sizes */
  color: var(--navy);
  margin: 0 0 0.4em;
  font-weight: 600;
}

.article h2 {
  font-family: var(--serif-display);
  font-size: 1.45em;
  line-height: 1.22;
  color: var(--navy);
  margin: 2em 0 0.5em;
  font-weight: 600;
}

.article .subtitle {
  font-size: 1.15em;
  color: var(--muted);
  margin: 0 0 1.6em;
  line-height: 1.4;
}

.article p { margin: 0 0 1.35em; }

.article a {
  color: var(--blue);
  text-decoration-thickness: 1px;
  text-underline-offset: 2px;
}

.article blockquote {
  margin: 1.6em 0;
  padding-left: 1.2em;
  border-left: 3px solid var(--rule);
  color: var(--muted);
}

.article pre {
  font-family: ui-monospace, 'Cascadia Code', Consolas, monospace;
  font-size: 0.82em;
  line-height: 1.5;
  background: rgba(11, 42, 74, 0.04);
  border: 1px solid var(--rule);
  border-radius: 4px;
  padding: 0.9em 1em;
  /* Wide content scrolls inside its own box; the page never scrolls
   * horizontally. */
  overflow-x: auto;
}

.article img,
.article video { max-width: 100%; height: auto; }

/* Images in a piece. A figure not yet verified holds its place quietly; one
 * that cannot be verified says so in words. Never a broken-image glyph. */
.body-img { margin: 2rem 0; }
.body-img img {
  display: block;
  width: 100%;
  border-radius: 3px;
  background: var(--rule);
  min-height: 6rem;
}
.body-img.loaded img { min-height: 0; background: transparent; }
.body-img figcaption {
  font-family: var(--sans);
  font-size: 0.76rem;
  color: var(--muted);
  margin-top: 0.5rem;
  text-align: center;
}
.body-img figcaption:empty { display: none; }
.body-img.missing {
  border: 1px dashed var(--rule);
  border-radius: 3px;
  padding: 1.2rem;
}
.body-extlink { font-family: var(--sans); font-size: 0.85rem; color: var(--muted); overflow-wrap: anywhere; }

/* ---------------------------------------------------------------------
   Controls
   --------------------------------------------------------------------- */

/* `.btn` is used by the MODALS as well as by the sign-in card. The card has
 * its own scoped copies above, in Chess's palette; these are the app-theme
 * versions for everything else. Both are needed - deleting these left every
 * settings button unstyled, which is how this comment came to exist. */
.btn {
  display: inline-block;
  font-family: var(--sans);
  font-size: 0.85rem;
  font-weight: 600;
  color: var(--paper);
  background: var(--navy);
  border: 1px solid var(--navy);
  border-radius: 6px;
  padding: 0.5rem 1rem;
  cursor: pointer;
  text-align: center;
}

.btn.wide { display: block; width: 100%; }
.btn.ghost { background: transparent; color: var(--blue); border-color: var(--rule); font-weight: 500; }
.btn.gold { background: var(--navy); }
.btn.sm { font-size: 0.76rem; padding: 0.35rem 0.7rem; }
.btn[disabled] { opacity: 0.5; cursor: default; }
/* The danger variant exists for exactly one class of act: the irreversible.
 * If it appears anywhere reversible, that is a bug (Chess uses it the same
 * way). */
.btn.danger { background: #c62828; }
.btn.danger[disabled] { background: #c62828; }

button,
.button {
  font-family: var(--sans);
  font-size: 0.85rem;
  color: var(--paper);
  background: var(--navy);
  border: 1px solid var(--navy);
  border-radius: 4px;
  padding: 0.5rem 0.95rem;
  cursor: pointer;
}

button.quiet,
.button.quiet {
  background: transparent;
  color: var(--blue);
  border-color: var(--rule);
}

button[disabled] { opacity: 0.5; cursor: default; }

/* 17.5: visible keyboard focus. Uses the bright blue, which is a large
 * non-text indicator and passes the 3:1 threshold that applies to it. */
:focus-visible {
  outline: 3px solid var(--blue-bright);
  outline-offset: 2px;
}

/* ---------------------------------------------------------------------
   Chain-derived values
   --------------------------------------------------------------------- */

/* I-16: the client never decides value. A figure that has not arrived from
 * the chain renders as '-', never as a default or a zero. The dimmed style
 * makes a pending figure visibly pending rather than looking like a real
 * result of nothing. */
.profTop { display: flex; align-items: center; }

#modal textarea {
  width: 100%;
  font-family: var(--sans);
  font-size: 0.88rem;
  color: var(--ink);
  background: transparent;
  border: 1px solid var(--rule);
  border-radius: 6px;
  padding: 0.55rem 0.7rem;
  resize: vertical;
}

/* Embedded attachments in the EDITOR: the picture in the page, atomic and
   quietly furnished. The name rides in CSS content so the figure contributes
   no text to the document model. */
.ed-embed {
  position: relative;
  margin: 1.4rem 0;
  max-width: 100%;
}

.ed-embed img,
.ed-embed video {
  display: block;
  max-width: 100%;
  max-height: 320px;
  border-radius: 6px;
}

.ed-embed video { background: #000; }
.ed-embed audio { display: block; width: 100%; }

.ed-embed::after {
  content: attr(data-name);
  display: block;
  font-family: var(--sans);
  font-size: 0.74rem;
  color: var(--muted);
  margin-top: 0.35rem;
}

.ed-embed.missing {
  border: 1px dashed var(--rule);
  border-radius: 6px;
  padding: 1rem;
}

.ed-embed-x {
  position: absolute;
  top: 0.4rem;
  right: 0.4rem;
  width: 1.6rem;
  height: 1.6rem;
  border: none;
  border-radius: 50%;
  background: rgba(10, 25, 47, 0.65);
  cursor: pointer;
  opacity: 0;
  transition: opacity 120ms;
}

.ed-embed:hover .ed-embed-x,
.ed-embed-x:focus-visible { opacity: 1; }

.ed-embed-x::before {
  content: '\00d7';
  color: #fff;
  font-size: 1rem;
  line-height: 1;
}

/* Video and audio in a body. Same figure furniture as an image so a mixed
   entry reads as one column. */
.body-media { margin: 1.6rem 0; }

.body-media video {
  display: block;
  width: 100%;
  max-height: 70vh;
  border-radius: 6px;
  background: #000;
}

.body-media audio { display: block; width: 100%; }

.body-media figcaption {
  font-family: var(--sans);
  font-size: 0.78rem;
  color: var(--muted);
  margin-top: 0.45rem;
}

.body-missing {
  font-family: var(--sans);
  font-size: 0.82rem;
  color: var(--muted);
  border-left: 3px solid var(--rule);
  padding-left: 0.8rem;
}

/* Forms inside a modal dialog. Bare labels and inputs flow INLINE in HTML,
 * which is what made the give-access dialog look like a ransom note (user
 * screenshot, 2026-08-05). Any dialog form gets the stacked treatment by
 * wrapping its fields in .mform - one class, consistent everywhere. */
.mform label {
  display: block;
  font-family: var(--sans);
  font-size: 0.82rem;
  color: var(--ink);
  margin: 0.95rem 0 0.3rem;
}

.mform input,
.mform textarea {
  display: block;
  width: 100%;
  box-sizing: border-box;
  font-family: var(--sans);
  font-size: 0.92rem;
  color: var(--ink);
  background: transparent;
  border: 1px solid var(--rule);
  border-radius: 6px;
  padding: 0.55rem 0.7rem;
}

.mform .setNote { margin-top: 0.9rem; }

/* The diary. Deliberately quieter than the public surfaces - it is a
 * private room, not a shopfront. Gold marks the locked/unlocked state,
 * which is the one thing a diarist must never misread. */
.diary-gate { max-width: 26rem; }
.diary-gate label { display: block; font-family: var(--sans); font-size: 0.82rem; margin: 0.9rem 0 0.3rem; }
/* Air between the last field and the button - they sat touching. */
.diary-gate .btn { margin-top: 1.2rem; }
.diary-gate .fieldErr { margin: 0.8rem 0 0; }
.diary-gate input {
  width: 100%;
  font-family: var(--sans);
  font-size: 0.9rem;
  color: var(--ink);
  background: transparent;
  border: 1px solid var(--rule);
  border-radius: 6px;
  padding: 0.5rem 0.7rem;
}

.diary-list { border-top: 1px solid var(--rule); margin-top: 1.4rem; }

.diary-row {
  display: flex;
  align-items: baseline;
  gap: 0.8rem;
  border-bottom: 1px solid var(--rule);
  padding: 0.2rem 0;
  flex-wrap: wrap;
}

.diary-open {
  flex: 1;
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 1rem;
  background: none;
  border: none;
  text-align: left;
  cursor: pointer;
  padding: 0.85rem 0.25rem;
  color: inherit;
}

.diary-open:hover .diary-title { color: var(--blue); }

.diary-title {
  font-family: var(--serif-display);
  font-size: 1.1rem;
  color: var(--navy);
}

.diary-date { font-size: 0.74rem; color: var(--muted); white-space: nowrap; }

.diary-body {
  flex-basis: 100%;
  padding: 0.2rem 0.25rem 1.1rem;
  font-family: var(--serif-body);
  font-size: var(--body-size);
  line-height: var(--leading);
  border-left: 3px solid var(--gold);
  margin: 0 0 0.6rem 0.25rem;
  padding-left: 0.9rem;
}

.diary-body[hidden] { display: none; }

.settingsec-h {
  font-family: var(--sans);
  font-size: 0.72rem;
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--muted);
  margin: 1.4rem 0 0.5rem;
}

/* The waiting state. Motion is the whole point - a static line during a
 * wait is what made the app look stuck - so it is deliberately small and
 * calm, and it respects reduced-motion like everything else. */
.loading {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  font-family: var(--sans);
  font-size: 0.85rem;
  color: var(--muted);
  padding: 1.5rem 0;
}

.loading-dots { display: inline-flex; gap: 4px; }

.loading-dots i {
  width: 5px;
  height: 5px;
  border-radius: 50%;
  background: var(--muted);
  opacity: 0.35;
  animation: loadingPulse 1.1s ease-in-out infinite;
}

.loading-dots i:nth-child(2) { animation-delay: 0.16s; }
.loading-dots i:nth-child(3) { animation-delay: 0.32s; }

@keyframes loadingPulse {
  0%, 80%, 100% { opacity: 0.25; transform: translateY(0); }
  40% { opacity: 1; transform: translateY(-3px); }
}

.figure { font-family: var(--sans); font-variant-numeric: tabular-nums; }
.figure.pending { color: var(--muted); }

/* ---------------------------------------------------------------------
   Editor
   --------------------------------------------------------------------- */

/* Distraction-free by default: a title, the text, and one quiet bar. The
 * formatting tools exist only over a selection. */

.edbar {
  position: sticky;
  top: 0;
  z-index: 10;
  display: flex;
  align-items: center;
  gap: 1rem;
  padding: 0.55rem 1.25rem;
  background: var(--paper);
  border-bottom: 1px solid var(--rule);
  font-family: var(--sans);
  font-size: 0.78rem;
  color: var(--muted);
}

.edbar-back {
  color: var(--blue);
  text-decoration: none;
  white-space: nowrap;
}
.edbar-back:hover { text-decoration: underline; }

.edbar-state {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  min-width: 0;
  flex: 1;
  white-space: nowrap;
  overflow: hidden;
}

.edbar-dot { width: 3px; height: 3px; border-radius: 50%; background: var(--rule); flex: none; }

.edbar-actions {
  display: flex;
  align-items: center;
  gap: 0.7rem;
  white-space: nowrap;
}

.edbar-quiet { color: var(--muted); font-size: 0.72rem; }
.edbar-quiet:empty { display: none; }

.editor-wrap {
  max-width: var(--measure);
  margin: 0 auto;
  padding: 2.5rem 1.25rem 8rem;
}

.title-input {
  display: block;
  width: 100%;
  border: none;
  outline: none;
  background: transparent;
  resize: none;
  overflow: hidden;
  padding: 0;
  font-family: var(--serif-display);
  font-size: 2.2em;
  line-height: 1.15;
  letter-spacing: -0.02em;
  color: var(--navy);
  margin-bottom: 1.2rem;
}

.title-input::placeholder { color: var(--muted); opacity: 0.55; }

.editor {
  min-height: 55vh;
  outline: none;
  font-family: var(--serif-body);
  font-size: var(--body-size);
  line-height: var(--leading);
  color: var(--ink);
  /* THE TEXT MODEL: newlines are real characters and must render as such.
   * Without this, a loaded draft's paragraphs collapse into one line. */
  white-space: pre-wrap;
  overflow-wrap: break-word;
}

.editor:empty::before {
  content: attr(data-placeholder);
  color: var(--muted);
  opacity: 0.55;
}

/* The selection toolbar - present only over a selection, floats above it. */
.edtools {
  position: absolute;
  z-index: 30;
  display: flex;
  align-items: center;
  gap: 2px;
  padding: 4px;
  background: var(--navy);
  border-radius: 8px;
  box-shadow: 0 6px 24px rgba(11, 42, 74, 0.35);
}

.edtools[hidden] { display: none; }

.edtool {
  font-family: var(--sans);
  font-size: 0.8rem;
  line-height: 1;
  color: var(--paper);
  background: transparent;
  border: none;
  border-radius: 5px;
  padding: 7px 9px;
  cursor: pointer;
  min-width: 30px;
}

.edtool:hover { background: rgba(255, 255, 255, 0.14); }
.edtool b, .edtool i { font-family: var(--serif-body); }

.edtools-rule { width: 1px; align-self: stretch; margin: 4px 3px; background: rgba(255, 255, 255, 0.25); }

/* Preview renders through the article styles - it IS the article. */
.edpreview { padding-top: 0; }
.edpreview[hidden] { display: none; }

/* First-run guidance (12.2): a quiet card, not a tour and not a modal. */
.edguide,
.dguide {
  max-width: var(--measure);
  margin: 1.5rem auto 0;
  padding: 1.1rem 1.25rem;
  border: 1px solid var(--rule);
  border-left: 3px solid var(--gold);
  border-radius: 6px;
  font-family: var(--sans);
  font-size: 0.85rem;
  line-height: 1.55;
  color: var(--ink);
}

.edguide h2,
.dguide h2 {
  font-family: var(--serif-display);
  font-size: 1.15rem;
  color: var(--navy);
  margin: 0 0 0.6rem;
}

.edguide p,
.dguide p { margin: 0 0 0.6rem; }
.edguide b,
.dguide b { color: var(--navy); }

/* The diary's copy of the guide sits inside .article, which already has its
 * own measure - so it fills that rather than imposing a second one. */
.dguide { max-width: none; margin: 1.2rem 0 0; }

/* ---------------------------------------------------------------------
   The diary's header row and list actions
   --------------------------------------------------------------------- */

.desk-head {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: 1rem;
  margin-bottom: 2.2rem;
}

.desk-head h1 {
  font-family: var(--serif-display);
  font-size: 2rem;
  line-height: 1.1;
  letter-spacing: -0.02em;
  color: var(--navy);
  margin: 0 0 0.3rem;
}

.desk-id {
  font-family: var(--sans);
  font-size: 0.8rem;
  color: var(--muted);
  margin: 0;
}

.desk-row-act {
  flex: none;
  font-family: var(--sans);
  font-size: 0.72rem;
  color: var(--muted);
  background: transparent;
  border: 1px solid var(--rule);
  border-radius: 4px;
  padding: 0.25rem 0.55rem;
  cursor: pointer;
  opacity: 0;
  transition: opacity 0.12s ease;
}

/* The reveal is bound to the DIARY row - a quiet action that appears when
 * the row is hovered or focused, and is simply always there on touch. */
.desk-row-act:focus-visible { opacity: 1; }
.diary-row:hover .desk-row-act,
.diary-row:focus-within .desk-row-act { opacity: 1; }

.desk-row-act:hover { color: var(--ink); border-color: var(--muted); }

/* Touch screens have no hover: the action is simply always there. */
@media (hover: none) {
  .desk-row-act { opacity: 1; }
}

.desk-empty {
  font-family: var(--sans);
  font-size: 0.85rem;
  color: var(--muted);
  padding: 0.85rem 0.25rem;
  border-bottom: 1px solid var(--rule);
  margin: 0;
}

.desk-empty a { color: var(--blue); }

@media (max-width: 34rem) {
  .desk-head { flex-direction: column; align-items: flex-start; }
}

/* ---------------------------------------------------------------------
   Quality floor
   --------------------------------------------------------------------- */

@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation-duration: 0.001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.001ms !important;
    scroll-behavior: auto !important;
  }
}

@media (max-width: 34rem) {
  .article,
  .editor-wrap { padding-left: 1rem; padding-right: 1rem; }
  .article h1 { font-size: 1.9em; }
  .edbar { flex-wrap: wrap; gap: 0.5rem; padding: 0.5rem 1rem; }
  .edbar-state { order: 3; flex-basis: 100%; }
}

/* ---------------------------------------------------------------------
   Paper-diary import: the page and its words, side by side
   --------------------------------------------------------------------- */

.desk-acts { display: flex; gap: 0.5rem; align-items: center; }

.dimp {
  display: grid;
  grid-template-columns: minmax(0, 5fr) minmax(0, 4fr);
  gap: 1.25rem;
  margin: 1rem 0;
}
.dimp-img {
  margin: 0;
  border: 1px solid var(--rule);
  border-radius: 8px;
  overflow: hidden;
  background: var(--paper);
  align-self: start;
}
.dimp-img img { display: block; width: 100%; height: auto; }
.dimp-side { display: flex; flex-direction: column; gap: 0.75rem; min-width: 0; }
.dimp-text {
  min-height: 16rem;
  resize: vertical;
  font: inherit;
  color: var(--ink);
  padding: 0.75rem;
  border: 1px solid var(--rule);
  border-radius: 8px;
  background: var(--paper);
}
.dimp-acts {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
  justify-content: space-between;
  align-items: center;
}
.dimp-nav { display: flex; gap: 0.5rem; }
.dimp-done { display: flex; justify-content: flex-end; margin: 1rem 0 2rem; }
.dimp-again { display: flex; gap: 0.5rem; align-items: center; }

.dimp-last { max-width: 28rem; margin: 1rem auto; }
.dimp-snap-acts { justify-content: space-between; flex-wrap: wrap; gap: 0.5rem; }

@media (max-width: 700px) {
  .dimp { grid-template-columns: 1fr; }
}

/* ---------------------------------------------------------------------
   The audience squares - who can read this entry
   --------------------------------------------------------------------- */

/* One square per guest, in the editor bar. Selected reads as a pressed
 * button (filled, initial in paper); deselected hollows out and dims. The
 * three slot colours are fixed so "the green one is Mum" stays true across
 * sessions. */
.ed-audience { display: inline-flex; gap: 5px; align-items: center; }
.ed-audience:empty { display: none; }

.aud-chip {
  width: 26px;
  height: 26px;
  padding: 0;
  border-radius: 7px;
  font-family: var(--sans);
  font-size: 0.72rem;
  font-weight: 700;
  line-height: 1;
  cursor: pointer;
  border: 2px solid transparent;
  color: var(--paper);
  opacity: 1;
}

.aud-c0 { background: var(--navy); border-color: var(--navy); }
.aud-c1 { background: #0b6ad4; border-color: #0b6ad4; }
.aud-c2 { background: #2e7d32; border-color: #2e7d32; }

.aud-chip:not(.on) {
  background: transparent;
  opacity: 0.55;
}
.aud-c0:not(.on) { color: var(--navy); }
.aud-c1:not(.on) { color: #0b6ad4; }
.aud-c2:not(.on) { color: #2e7d32; }

/* ---------------------------------------------------------------------
   The background picker
   --------------------------------------------------------------------- */

.bggrid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(5.4rem, 1fr));
  gap: 0.5rem;
  margin-top: 0.6rem;
}

.bgtile {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.35rem;
  padding: 0.5rem 0.3rem 0.45rem;
  background: transparent;
  color: var(--ink);
  border: 1px solid var(--rule);
  border-radius: 8px;
  cursor: pointer;
}

.bgtile.on { border-color: var(--navy); box-shadow: 0 0 0 1px var(--navy); }

.bgtile-swatch {
  display: block;
  width: 100%;
  height: 3.2rem;
  border-radius: 5px;
  background-color: var(--paper);
  border: 1px solid var(--rule);
}

.bgtile-label { font-family: var(--sans); font-size: 0.68rem; }

.bgswatches {
  display: flex;
  flex-wrap: wrap;
  gap: 0.45rem;
  align-items: center;
}

.bgswatch {
  width: 26px;
  height: 26px;
  padding: 0;
  border: 2px solid transparent;
  border-radius: 50%;
  cursor: pointer;
}

.bgswatch.on { border-color: var(--ink); box-shadow: 0 0 0 2px var(--paper) inset; }

.bgcustom {
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  font-family: var(--sans);
  font-size: 0.74rem;
  color: var(--muted);
  cursor: pointer;
}
.bgcustom input { width: 26px; height: 26px; padding: 0; border: 1px solid var(--rule); border-radius: 6px; background: transparent; cursor: pointer; }

.bgslider { display: flex; align-items: center; gap: 0.8rem; }
.bgslider input[type="range"] { flex: 1; }
.bgslider .setNote { margin: 0; white-space: nowrap; }
