:root{
  color-scheme:light;
  --ink:#1C2A20; --ink-2:#3C4A40; --ink-3:#625D4F;
  --moss:#38523E;
  --moss-deep:#24382A;
  --sage:#7E9179;
  --gold:#C39B3E;
  --gold-pale:#EFE2C0; --gold-ink:#1C2A20;
  --blue:#2C6E8F;
  --blue-pale:#DCE9F0;
  --paper:#F6F2E7;
  --paper-2:#EDE6D4;
  --card:#FCFAF3;
  --line:#D9CFB6; --line-2:#E8E0CC;
  --danger:#A8452F; --danger-pale:#F6E3DD;
  --ok:#3F7A4E; --ok-pale:#DDEBDF;
  --shadow:0 2px 0 rgba(28,42,32,.06);
  --scrim:rgba(28,42,32,.55);
  --skeleton:linear-gradient(90deg,var(--paper-2) 25%,var(--line-2) 50%,var(--paper-2) 75%);
  --r:10px;
  /* Type scale: six steps from a 15px body. New rules use these; the old literal
     sizes are being folded into them as each screen is touched. */
  --t-xs:12px; --t-s:13px; --t-m:15px; --t-l:18px; --t-xl:22px; --t-xxl:27px;
  /* Fixed in both themes: the deep-green header/gate surface, and what sits on it or
     on a person's own colour. A family colour is a constant, so its text must be too. */
  --deep:#24382A; --on-deep:#F6F2E7; --gold-on-deep:#EFE2C0;
  /* Secondary text. --sage stays for borders, swatches and the map; it was never dark
     enough to read small (3:1 on paper). --gold-text is gold you can read. */
  --muted:#5E6858; --gold-text:#8A6A1E;
  --sans:'Archivo',system-ui,-apple-system,'Segoe UI',sans-serif;
  --serif:'Fraunces',Georgia,serif;
}
/* Dark is a second set of values, not a second stylesheet. data-theme is the person's
   choice from Profile; with no choice the phone decides. */
:root[data-theme="dark"],
:root:not([data-theme="light"]).sysdark{
  color-scheme:dark;
  --ink:#EEE9DB; --ink-2:#C9C3B2; --ink-3:#9AA096;
  --moss:#8FB097; --moss-deep:#1F2E24; --sage:#94A894;
  --gold:#D7B35C; --gold-pale:#3A3220; --gold-ink:#1C2A20;
  --blue:#7FB6D3; --blue-pale:#1E3440;
  --paper:#161D18; --paper-2:#1F2821; --card:#1C241E;
  --line:#33413A; --line-2:#28332C;
  --danger:#E07A63; --danger-pale:#3C221C;
  --ok:#7FBF8C; --ok-pale:#1F3324;
  --shadow:0 2px 0 rgba(0,0,0,.3);
  --scrim:rgba(0,0,0,.6);
  --skeleton:linear-gradient(90deg,#28332C 25%,#3A4840 50%,#28332C 75%);
  --muted:#9AA896; --gold-text:#D7B35C;
}
*{box-sizing:border-box}
html{height:100%;overflow:hidden}
html,body{margin:0;padding:0}
body{
  font-family:var(--sans);
  background:var(--paper);
  color:var(--ink);
  font-size:15px;
  line-height:1.5;
  -webkit-text-size-adjust:100%;
  overscroll-behavior-y:none;
  /* The page itself never scrolls — only .view does. Letting the document scroll made
     the whole thing feel loose on a phone: the address bar grew and shrank, and a drag
     begun on the map got handed to the page halfway through.

     body was position:fixed/inset:0, which is a second way of saying "fill the
     viewport" and one iOS has never been reliable about in a Home Screen app — a
     position:fixed child inside it does not always reach the real bottom of the
     screen. html and body at height:100% with overflow hidden achieves the same thing
     (the page cannot scroll, only .view does) and leaves fixed children positioning
     against a clean viewport, which is what the tab bar needs. */
  height:100%;
  overflow:hidden;
  touch-action:manipulation;
}
button,input,select,textarea{font:inherit;color:inherit}
button{cursor:pointer;border:none;background:none}
a{color:var(--blue)}
h1,h2,h3{font-family:var(--serif);font-weight:600;margin:0;line-height:1.15;letter-spacing:-.01em}
h1{font-size:26px}
h2{font-size:20px}
h3{font-size:16px}
p{margin:0 0 10px}
:focus-visible{outline:2px solid var(--blue);outline-offset:2px;border-radius:4px}
@media (prefers-reduced-motion:reduce){*{animation:none!important;transition:none!important}}

/* ---------- launch: the house going up ----------
   Not a spinner. Henry's own drawing of the house builds itself from the ground up —
   the ink first, then the colour washing through it — and the screen is taken away the
   moment the app has its data, or when the build finishes, whichever is later. */
.boot{position:fixed;inset:0;z-index:60;background:var(--paper);display:flex;
  align-items:center;justify-content:center;padding:24px;
  transition:opacity .5s ease,visibility .5s}
.boot.gone{opacity:0;visibility:hidden;pointer-events:none}
.bootin{width:min(88vw,460px);text-align:center}
.bootart{position:relative;width:100%;aspect-ratio:1195/896}
/* The house is drawn the way it would be drawn: the roof outlined and filled, then the
   walls, then the timber, the glass, and the ground it stands on. Each piece gets its
   own strokes (house-i1..5, split from the linework by scripts/split_ink.py) which
   sweep on over a third of a second, and its colour washes in just behind them.

   The whole run is about three seconds. That is deliberate — it is the app's loading
   time, and watching the house be drawn is a better use of it than a spinner. */
.bootart img{position:absolute;inset:0;width:100%;height:100%;display:block}
/* Nothing moves until .boot.ready is set, which the inline script in index.html does
   once every layer has decoded: strokes sweeping across images that have not arrived
   yet is what made the build look broken on a cold load. */
.bi{clip-path:inset(0 100% 0 0)}
.boot.ready .bi{animation:draw .34s ease-out forwards;
  animation-delay:calc(.25s + var(--n) * .52s)}
@keyframes draw{to{clip-path:inset(0 0 0 0)}}
/* The colour follows its own strokes rather than arriving with them, so for a moment
   each piece is just an outline — which is what makes it read as drawing. */
.bc{opacity:0}
.boot.ready .bc{animation:wash .4s ease forwards;animation-delay:calc(.52s + var(--n) * .52s)}
@keyframes wash{to{opacity:1}}
.bootword{font-family:var(--serif);font-size:29px;font-weight:600;letter-spacing:-.01em;
  margin:10px 0 0;color:var(--ink);opacity:0}
.boot.ready .bootword{animation:wash .5s ease 1.5s forwards}
.bootsub{font-size:11.5px;letter-spacing:.07em;text-transform:uppercase;color:var(--muted);
  margin:3px 0 0;opacity:0}
.boot.ready .bootsub{animation:wash .5s ease 1.7s forwards}
/* Someone who has asked for less movement gets the finished house, not the build. */
@media (prefers-reduced-motion:reduce){
  .bi,.boot.ready .bi{animation:none;clip-path:none}
  .bc,.bootword,.bootsub,.boot.ready .bc,.boot.ready .bootword,.boot.ready .bootsub{animation:none;opacity:1}
}

/* ---------- horizon band: island motif ---------- */
.horizon{height:4px;background:linear-gradient(90deg,var(--moss) 0%,var(--sage) 32%,var(--gold) 52%,var(--blue) 78%,var(--moss-deep) 100%)}

/* ---------- sign in ---------- */
.gate{height:100%;overflow-y:auto;-webkit-overflow-scrolling:touch;
  display:flex;flex-direction:column;background:var(--deep);color:var(--on-deep)}
.gate-art{position:relative;flex:0 0 auto;padding:44px 22px 26px;overflow:hidden}
.gate-art svg{position:absolute;left:0;right:0;bottom:-1px;width:100%;height:88px;display:block}
.gate-art .brand{position:relative;z-index:2}
.brandmark{font-family:var(--serif);font-size:46px;font-weight:600;letter-spacing:-.02em;color:var(--gold-on-deep);margin:0}
.brandsub{color:var(--muted);font-size:13.5px;margin:6px 0 0;max-width:30ch}
.gate-body{flex:1;background:var(--paper);color:var(--ink);border-radius:20px 20px 0 0;padding:24px 20px 40px;margin-top:-2px}
.welcome{font-family:var(--serif);font-size:23px;margin:0 0 2px}
.gate-note{color:var(--moss);font-size:13.5px;margin-bottom:18px}

/* ---------- forms ---------- */
.field{margin-bottom:13px}
.field label{display:block;font-size:12.5px;font-weight:600;color:var(--moss);margin-bottom:5px}
.field .hint{font-weight:400;color:var(--muted)}
input[type=text],input[type=email],input[type=tel],input[type=password],input[type=date],input[type=number],select,textarea{
  width:100%;padding:11px 12px;border:1px solid var(--line);border-radius:var(--r);
  background:var(--card);font-size:16px;
}
textarea{min-height:78px;resize:vertical;line-height:1.45}
input:disabled,select:disabled{background:var(--paper-2);color:var(--muted)}
.row{display:flex;gap:10px}
.row>*{flex:1;min-width:0}
.check{display:flex;align-items:center;gap:9px;font-size:14px;margin:4px 0 16px;cursor:pointer}
.check input{width:19px;height:19px;accent-color:var(--moss)}

.btn{display:inline-flex;align-items:center;justify-content:center;gap:7px;
  padding:12px 16px;border-radius:var(--r);font-weight:600;font-size:15px;width:100%;
  background:var(--moss);color:var(--paper);border:1px solid var(--moss);transition:filter .12s}
.btn:hover{filter:brightness(1.08)}
.btn:active{filter:brightness(.94)}
.btn.gold{background:var(--gold);border-color:var(--gold);color:var(--gold-ink)}
.btn.blue{background:var(--blue);border-color:var(--blue)}
.btn.ghost{background:transparent;color:var(--moss);border:1px solid var(--line)}
.btn.danger{background:transparent;color:var(--danger);border:1px solid #E0BFB6}
.btn.sm{padding:8px 11px;font-size:13.5px;width:auto}
.btn.auto{width:auto}
.btn:disabled{opacity:.45;cursor:not-allowed}
.btnrow{display:flex;gap:8px;flex-wrap:wrap}
.linkbtn{background:none;color:var(--blue);font-size:14px;font-weight:600;padding:6px 0;width:auto;text-decoration:underline;text-underline-offset:3px}

/* ---------- app shell ---------- */
.app{display:none;height:100%;flex-direction:column}
.app.on{display:flex}
/* The status bar sits over the header on an iPhone once the app is on the Home
   Screen — viewport-fit=cover means the page owns the full screen, so the header has
   to make room for it itself. */
.topbar{flex:0 0 auto;z-index:30;background:#24382A;color:#F6F2E7;
  padding-top:max(env(safe-area-inset-top), 8px)}
.topbar-in{display:flex;align-items:center;gap:10px;padding:13px 15px 14px}
.topbar h1{font-size:19px;color:#EFE2C0;flex:1;min-width:0;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.topmark{flex:0 0 auto;width:34px;height:34px;border-radius:9px;display:block;
  background:var(--paper);object-fit:cover;box-shadow:0 0 0 1px rgba(246,242,231,.22)}
.topbar .who{font-size:12px;color:var(--muted)}
.avatar{width:32px;height:32px;border-radius:50%;display:grid;place-items:center;overflow:hidden;
  font-size:12.5px;font-weight:700;color:var(--on-deep);flex:0 0 auto;letter-spacing:.02em}
.avatar img{width:100%;height:100%;object-fit:cover;display:block}
.avbtn{padding:0;border-radius:50%;line-height:0;border:2px solid rgba(239,226,192,.35)}
.qrbox{background:#fff;border:1px solid var(--line);border-radius:12px;padding:16px;text-align:center;margin-top:12px;color:#2A2110}
.qrbox .muted{color:#5A5A4A}
.qrbox canvas{width:200px;height:200px;max-width:100%}
.hours{font-size:12px;color:var(--moss);background:var(--paper-2);border-radius:6px;padding:1px 6px;display:inline-block;margin-top:3px}
.hours.shut{color:var(--danger);background:var(--danger-pale)}
.wxnow .wxmain{display:flex;align-items:center;gap:14px}
.wxicon{color:var(--moss);flex:0 0 auto}
.wxicon .ic{width:46px;height:46px;stroke-width:1.3}
.wxsym .ic{width:19px;height:19px;margin:0 auto;color:var(--moss);stroke-width:1.5}
.wxtemp{font-family:var(--serif);font-size:38px;margin:0;line-height:1}
.wxgrid{display:grid;grid-template-columns:1fr 1fr;gap:8px 14px;margin-top:14px;
  border-top:1px solid var(--line);padding-top:12px}
.wxgrid div{display:flex;justify-content:space-between;gap:8px;font-size:13.5px}
.wxgrid span{color:var(--muted)}
.wxweek{display:grid;grid-template-columns:repeat(7,1fr);gap:2px;text-align:center}
.wxday{display:flex;flex-direction:column;gap:2px;padding:6px 0;border-radius:8px;background:var(--paper-2)}
.wxdow{font-size:10.5px;font-weight:700;color:var(--muted)}
.wxsym{line-height:1}
.wxhi{font-size:13px;font-weight:700}
.wxlo{font-size:11.5px;color:var(--muted)}
.wxrain{font-size:10px;color:var(--blue);font-weight:600}
.tidebig{font-family:var(--serif);font-size:34px;margin:2px 0 0;line-height:1}
/* The tide curve. preserveAspectRatio is off so it stretches to the card width — the
   shape matters, the exact proportions do not. */
.tidecard h3{font-size:17px}
.tidesvg{display:block;width:100%;height:112px;margin:6px 0 0;overflow:visible}
.tcl{font-family:var(--sans);font-size:8px;font-weight:700;fill:var(--sage)}
.tcday{font-family:var(--sans);font-size:8px;font-weight:700;fill:var(--ink-3)}
.tcmid{stroke:var(--line);stroke-width:1;stroke-dasharray:2 3}
.tcnow{stroke:var(--danger);stroke-width:1.2;stroke-dasharray:3 3;opacity:.75}
#guest{display:none;height:100%;overflow-y:auto;-webkit-overflow-scrolling:touch}
#guest.on{display:block}
#guest .view{padding-bottom:40px}
.guesttop{background:var(--deep);color:var(--on-deep);padding:14px 15px;
  padding-top:max(env(safe-area-inset-top), 14px);display:flex;align-items:center;gap:10px}
.guesttop .topmark{width:30px;height:30px}
.guesttop p{margin:0;font-family:var(--serif);font-size:20px;color:var(--gold-on-deep)}
.guesttop span{font-size:12px;color:var(--muted)}
/* The one scrolling region in the app. Content that genuinely does not fit — the help
   articles, the house guides — scrolls inside here, and the header and tabs never move
   while it does. */
/* The one scrolling region. Its bottom padding clears the fixed tab bar, so the last
   row of a list can still be read and tapped rather than sitting under it. */
.view{flex:1;min-height:0;overflow-y:auto;-webkit-overflow-scrolling:touch;
  overscroll-behavior:contain;max-width:760px;margin:0 auto;width:100%;
  padding:16px 15px calc(86px + env(safe-area-inset-bottom))}
/* Welded to the bottom of the screen, not handed down a chain of flex children.
   Making it a flex child meant it sat wherever html → body → .app → .tabs happened to
   resolve to, and on an iPhone running from the Home Screen that came up about a
   centimetre short. bottom:0 cannot come up short. */
.tabs{position:fixed;left:0;right:0;bottom:calc(-1 * var(--tabgap, 0px));z-index:40;background:var(--paper);
  border-top:1px solid var(--line);display:flex;
  /* The home indicator needs about 21px of clearance, not the whole inset. Reserving
     all 34 of it plus padding left the labels sitting a centimetre off the bottom,
     which is most of what this looked like. */
  padding:6px 4px calc(4px + max(8px, env(safe-area-inset-bottom) - 10px))}
.tab{flex:1;display:flex;flex-direction:column;align-items:center;gap:3px;padding:6px 2px;
  font-size:10.5px;font-weight:600;color:var(--muted);border-radius:8px}
.tab svg{width:21px;height:21px;stroke:currentColor;fill:none;stroke-width:1.7;stroke-linecap:round;stroke-linejoin:round}
.tab.on{color:var(--moss)}
.tab.on svg{stroke:var(--moss)}
.tab .dot{position:absolute;transform:translate(13px,-4px);width:7px;height:7px;border-radius:50%;background:var(--gold)}

/* ---------- cards ---------- */
.card{background:var(--card);border:1px solid var(--line);border-radius:12px;padding:14px;margin-bottom:12px;box-shadow:var(--shadow)}
.card.flat{background:var(--paper-2);border-color:transparent;box-shadow:none}
.card h3{margin-bottom:6px}
.sec-head{display:flex;align-items:baseline;gap:10px;margin:22px 0 10px}
.sec-head:first-child{margin-top:0}
.sec-head h2{flex:1}
.sec-head .count{font-size:12.5px;color:var(--muted);font-weight:600}
.muted{color:var(--muted);font-size:13px}
.empty{border:1px dashed var(--line);border-radius:12px;padding:22px 16px;text-align:center;color:var(--moss);background:var(--paper-2)}
.empty strong{display:block;font-family:var(--serif);font-size:17px;margin-bottom:4px}

.pill{display:inline-flex;align-items:center;gap:5px;font-size:11.5px;font-weight:700;
  padding:3px 8px;border-radius:99px;background:var(--paper-2);color:var(--moss)}
.pill.locked{background:var(--moss);color:var(--paper)}
.pill.placeholder{background:repeating-linear-gradient(135deg,var(--gold-pale) 0 5px,#fff 5px 10px);color:var(--ink);border:1px solid var(--gold)}
.pill.blue{background:var(--blue-pale);color:var(--blue)}
.pill.warn{background:var(--danger-pale);color:var(--danger)}
.pill.ok{background:var(--ok-pale);color:var(--ok)}

/* ---------- calendar ---------- */
.calbar{display:flex;align-items:center;gap:8px;margin-bottom:12px}
.calbar h2{flex:1;text-align:center;font-size:19px}
.navbtn{width:38px;height:38px;border-radius:10px;border:1px solid var(--line);background:var(--card);
  display:grid;place-items:center;font-size:18px;color:var(--moss);flex:0 0 auto}
.dow{display:grid;grid-template-columns:repeat(7,1fr);gap:1px;margin-bottom:1px}
.dow span{text-align:center;font-size:10.5px;font-weight:700;color:var(--muted);padding:5px 0}
.dow span.we{color:var(--gold-text)}
/* A week is a positioned row: seven day buttons for the numbers and the taps, with the
   ribbons laid over the top. Rows are only as tall as the busiest week needs, which is
   what gets the whole month back onto one screen. */
.cal{display:flex;flex-direction:column;border:1px solid var(--line);
  border-radius:12px;overflow:hidden;background:var(--card)}
.wk{position:relative}
.wk + .wk{border-top:1px solid var(--line)}
.wkdays{display:grid;grid-template-columns:repeat(7,1fr);position:absolute;inset:0}
.day{background:transparent;padding:3px 0 0;position:relative;text-align:center;
  display:block;width:100%;border-right:1px solid var(--line);vertical-align:top}
.day:last-child{border-right:0}
.day.out .num{color:var(--ink-3);opacity:.65}
.day.we{background:rgba(195,155,62,.05)}
.day.out{background:rgba(0,0,0,.025)}
/* Pinned to the top of the cell rather than left to the button's own centring, which
   is what put the numbers underneath the ribbons instead of above them. */
.num{position:absolute;top:3px;left:50%;transform:translateX(-50%);
  display:grid;place-items:center;width:21px;height:21px;border-radius:50%;
  font-size:12.5px;font-weight:600;color:var(--ink);line-height:1}
.day.today .num{background:var(--blue);color:var(--paper);font-weight:700}

/* The ribbon. Rounded where the stay really begins and ends, square where it carries
   on into the week next door — so a long stay reads as one thing across two rows. */
.rib{position:absolute;height:13px;z-index:2;border-radius:7px;
  background:var(--c);color:var(--on-deep);font-size:9.5px;font-weight:700;line-height:13px;
  padding:0 6px;overflow:hidden;white-space:nowrap;text-overflow:ellipsis;
  box-shadow:0 1px 0 rgba(0,0,0,.06)}
.rib.ol{border-top-left-radius:0;border-bottom-left-radius:0}
.rib.or{border-top-right-radius:0;border-bottom-right-radius:0}
/* A placeholder is an outline: it is a held date, not a settled one, and it should
   look lighter than the thing it might become. */
.rib.ph{background:transparent;color:var(--ink);
  box-shadow:inset 0 0 0 1.5px var(--c);
  background-image:repeating-linear-gradient(135deg, color-mix(in srgb, var(--c) 22%, transparent) 0 4px, transparent 4px 8px)}

.legend{display:flex;flex-wrap:wrap;gap:8px 14px;margin-top:12px;font-size:12px;color:var(--moss)}
.legend i{display:inline-block;width:11px;height:11px;border-radius:3px;margin-right:5px;vertical-align:-1px}
.legend .legph{background:repeating-linear-gradient(135deg,var(--moss) 0 3px,rgba(56,82,62,.35) 3px 6px)}
.legend .legnote{color:var(--muted);font-size:11.5px}

/* House events on the calendar. Gold for an event, a hatched red for a closure, so
   neither can be mistaken for somebody's stay; both fixed-ink text over fixed fills,
   which is why they do not use the theme tokens. */
.rib.ev.event{background:var(--gold);color:#2A2110}
.rib.ev.closed{background:repeating-linear-gradient(135deg,#B9574A 0 4px,#8F3D32 4px 8px);color:#FBEDE8}
.legend .legev{background:var(--gold)}
.legend .legclosed{background:repeating-linear-gradient(135deg,#B9574A 0 3px,#8F3D32 3px 6px)}
.swatch.ev.event{background:var(--gold)}
.swatch.ev.closed{background:repeating-linear-gradient(135deg,#B9574A 0 4px,#8F3D32 4px 8px)}
.pill.event{background:var(--gold);color:#2A2110}
.pill.closed{background:#A8452F;color:#FBEDE8}

/* The noticeboard card at the top of the calendar. */
.notice{border-color:var(--gold);border-left-width:5px}
.notice-kicker{font-size:11px;font-weight:700;letter-spacing:.06em;text-transform:uppercase;color:var(--gold-text);margin-bottom:3px}
.notice-title{font-size:15.5px;font-weight:700;color:var(--ink);margin-bottom:3px}
.notice-body{font-size:13.5px;line-height:1.45;color:var(--ink-2);white-space:pre-wrap}

/* The month is the point of the app, so on a phone it runs closer to the edges.

   This used to force .day to 94px here as well, left over from when every cell was a
   tall box. The weeks size themselves now, so all that rule did was make every cell
   twice its row's height and hang over the week below — invisible while the cells were
   transparent, and a tap near the bottom of a day landed on the wrong day. */
@media (max-width:520px){
  .calwide{margin-left:-9px;margin-right:-9px}
  .view{padding-left:12px;padding-right:12px}
}

/* ---------- booking list ---------- */
.bk{display:flex;gap:11px;align-items:flex-start;padding:12px 0;border-bottom:1px solid var(--line)}
.bk:last-child{border-bottom:0}
.bk-main{flex:1;min-width:0}
.bk-when{font-family:var(--serif);font-size:15.5px;font-weight:600}
.bk-meta{font-size:12.5px;color:var(--muted);margin-top:2px}
.swatch{width:5px;align-self:stretch;border-radius:99px;flex:0 0 auto;min-height:34px}

/* ---------- contacts & guides ---------- */
.ct{display:flex;align-items:center;gap:11px;padding:11px 0;border-bottom:1px solid var(--line)}
.ct:last-child{border-bottom:0}
.ct-main{flex:1;min-width:0}
.ct-name{font-weight:600;font-size:15px}
.ct-role{font-size:12.5px;color:var(--muted)}
.iconbtn{width:38px;height:38px;border-radius:10px;border:1px solid var(--line);background:var(--paper);
  display:grid;place-items:center;flex:0 0 auto;color:var(--moss);text-decoration:none}
.iconbtn svg{width:18px;height:18px;stroke:currentColor;fill:none;stroke-width:1.8;stroke-linecap:round;stroke-linejoin:round}
.iconbtn.blue{background:var(--blue-pale);border-color:#BBD5E3;color:var(--blue)}
.iconbtn.gold{background:var(--gold-pale);border-color:#DCC98E;color:var(--ink)}
details.guide{border:1px solid var(--line);border-radius:12px;background:var(--card);margin-bottom:9px;overflow:hidden}
details.guide>summary{padding:13px 14px;font-weight:600;cursor:pointer;list-style:none;
  display:flex;align-items:center;gap:10px;font-size:15px}
details.guide>summary::-webkit-details-marker{display:none}
details.guide>summary .chev{margin-left:auto;color:var(--muted);transition:transform .15s}
details.guide[open]>summary{background:var(--paper-2)}
details.guide[open]>summary .chev{transform:rotate(90deg)}
.guide-body{padding:4px 14px 14px;font-size:14px}
.guide-body ol,.guide-body ul{margin:6px 0 10px;padding-left:20px}
.guide-body li{margin-bottom:5px}
.caution{background:var(--danger-pale);border-left:3px solid var(--gold);padding:9px 11px;border-radius:0 8px 8px 0;font-size:13.5px;margin:8px 0}
.gicon{width:30px;height:30px;border-radius:8px;background:var(--gold-pale);color:var(--ink);
  display:grid;place-items:center;flex:0 0 auto}
.ic{width:17px;height:17px;stroke:currentColor;fill:none;stroke-width:1.6;
  stroke-linecap:round;stroke-linejoin:round;display:block}
.iconpick{display:grid;grid-template-columns:repeat(6,1fr);gap:6px;margin-top:4px}
.iconpick button{aspect-ratio:1;border:1px solid var(--line);border-radius:9px;background:var(--card);
  color:var(--moss);display:grid;place-items:center}
.iconpick button .ic{width:19px;height:19px}
.iconpick button[aria-pressed=true]{background:var(--moss);border-color:var(--moss);color:var(--paper)}

/* ---------- modal ---------- */
.scrim{position:fixed;inset:0;z-index:100;display:none;
  align-items:flex-end;justify-content:center;padding:0;
  background:rgba(28,42,32,calc(.55 * var(--dim, 1)))}
.scrim.on{display:flex}
.sheet{background:var(--paper);width:100%;max-width:560px;max-height:88dvh;overflow:auto;
  border-radius:18px 18px 0 0;padding:8px 18px calc(24px + env(safe-area-inset-bottom));
  overscroll-behavior:contain;touch-action:pan-y;will-change:transform}
/* The handle is the obvious place to grab, so give it a proper target rather than a
   4px line — the whole strip across the top drags. */
.sheet .grab{width:38px;height:4px;border-radius:99px;background:var(--line);
  margin:6px auto 14px;position:relative}
.sheet .grab::before{content:'';position:absolute;left:-140px;right:-140px;top:-12px;bottom:-14px}
.sheet.dragging{transition:none}
.sheet.settling{transition:transform .22s cubic-bezier(.2,0,.2,1)}
.scrim.closing{pointer-events:none}
.sheet h2{margin-bottom:8px}
@media(min-width:620px){.scrim{align-items:center;padding:20px}.sheet{border-radius:16px}}

.toast{position:fixed;left:50%;bottom:88px;transform:translateX(-50%) translateY(10px);z-index:200;
  background:var(--deep);color:var(--on-deep);padding:11px 16px;border-radius:99px;font-size:13.5px;
  font-weight:500;opacity:0;pointer-events:none;transition:opacity .2s,transform .2s;max-width:92vw;text-align:center}
.toast.on{opacity:1;transform:translateX(-50%) translateY(0)}

.banner{background:var(--gold-pale);border:1px solid var(--gold);border-radius:12px;padding:12px 13px;margin-bottom:14px;font-size:13.5px}
.banner strong{display:block;font-family:var(--serif);font-size:15px;margin-bottom:3px}
.banner.blue{background:var(--blue-pale);border-color:#A9CADB}

table.mini{width:100%;border-collapse:collapse;font-size:13.5px}
table.mini td{padding:7px 0;border-bottom:1px solid var(--line);vertical-align:top}
table.mini td:first-child{color:var(--muted);width:38%;padding-right:10px}
table.mini tr:last-child td{border-bottom:0}
.stack{display:flex;flex-direction:column;gap:8px}
.between{display:flex;align-items:center;gap:10px;justify-content:space-between}
hr.rule{border:0;border-top:1px solid var(--line);margin:18px 0}
.foot{text-align:center;color:var(--muted);font-size:11.5px;padding:18px 0 4px}

/* ---------- fishing ---------- */
.seg{display:flex;gap:3px;background:var(--paper-2);border-radius:10px;padding:3px;margin-bottom:14px}
.seg button{flex:1;padding:8px 4px;border-radius:8px;font-size:13px;font-weight:600;color:var(--moss)}
.seg button.on{background:var(--card);box-shadow:var(--shadow)}
.mapwrap{position:relative;border:1px solid var(--line);border-radius:12px;overflow:hidden;background:#BCD7E4}
#mapHost svg{display:block;width:100%;height:auto;max-height:74dvh;touch-action:none;
  cursor:crosshair;transform-origin:50% 50%;will-change:transform;backface-visibility:hidden}
#mapHost .mk{cursor:pointer}
#mapHost .placemark{cursor:pointer}
#mapHost .justlogged{animation:catchring 2.1s ease-out}
@keyframes catchring{
  0%{stroke:var(--gold);stroke-width:9}
  60%{stroke:var(--gold);stroke-width:3}
  100%{stroke:#F6F2E7}
}
@media (prefers-reduced-motion:reduce){#mapHost .justlogged{animation:none}}
/* Only crosshair while a pin is actually being asked for; the rest of the time this is
   a map you drag, and a crosshair over it promises a tap does something. */
#mapHost svg{cursor:grab}
.mapwrap.picking #mapHost svg{cursor:crosshair}

/* Pin mode: a band across the top of the map, not a toast, because it has to stay up
   for as long as it takes to find the spot. */
.pinmode{position:absolute;left:8px;right:8px;top:8px;z-index:3;display:none;
  align-items:center;gap:8px;padding:8px 10px;border-radius:10px;
  background:rgba(36,56,42,.94);color:var(--on-deep);box-shadow:var(--shadow)}
.pinmode.on{display:flex}
.pinmode span{flex:1;min-width:0;font-size:13px;font-weight:600}
.pinmode .btn{flex:0 0 auto;padding:5px 10px;font-size:12px}
.pinmode .btn.ghost{background:transparent;color:var(--gold-on-deep);border-color:rgba(246,242,231,.35)}

/* The fishing widget rides on the map and folds away to a pill. */
.fishw{position:absolute;left:8px;right:8px;bottom:8px;z-index:3;
  background:var(--card);border:1px solid var(--line);border-radius:12px;
  padding:10px 11px;box-shadow:var(--shadow);backdrop-filter:blur(6px)}
.fishw.shut{left:auto;right:8px;background:none;border:0;padding:0;box-shadow:none;backdrop-filter:none}
.fishw-top{display:flex;align-items:flex-start;gap:8px}
.fishw-head{flex:1;min-width:0}
.fishw-head strong{display:block;font-size:13.5px;line-height:1.25}
.fishw-head em{font-style:normal;font-size:11.5px;color:var(--muted)}
.fishw-shut{flex:0 0 auto;width:26px;height:26px;border-radius:7px;color:var(--muted);
  font-size:15px;line-height:1;background:var(--paper-2)}
.fishw-count{margin:6px 0 8px;font-size:11.5px;color:var(--muted)}
.fishpill{display:inline-flex;align-items:center;gap:7px;padding:7px 13px 7px 8px;
  border-radius:999px;background:rgba(246,242,231,.96);border:1px solid var(--line);
  box-shadow:var(--shadow);font-size:12.5px;font-weight:700;color:#1C2A20}

/* A tapped place. Sits under the map so it never covers the thing you just tapped. */
#placeCard{max-height:0;overflow:hidden;transition:max-height .2s ease}
#placeCard.on{max-height:120px}
.placecard{display:flex;align-items:center;gap:8px;margin:10px 0 2px;padding:10px 12px;
  border:1px solid var(--line);border-radius:12px;background:var(--card);box-shadow:var(--shadow)}
.placecard-main{flex:1;min-width:0}
.placecard-main strong{display:block;font-size:13.5px}
.placecard-main em{font-style:normal;font-size:11.5px;color:var(--muted)}
.placecard .btn{flex:0 0 auto;padding:6px 11px}
.maplayers{margin-bottom:8px}
/* Place labels: haloed so they stay readable over sand, water or mangrove alike.
   The chart itself is painted in fixed daytime colours (it is a map, not a page), so
   its labels are fixed too -- a theme token here turns the halo dark in dark mode and
   the words vanish into it. */
#mapHost .place text{font-family:var(--sans);paint-order:stroke fill;stroke:#F6F2E7;stroke-width:2.6px;stroke-linejoin:round}
#mapHost .pllabel{font-size:8.5px;font-weight:700;fill:#24382A}
#mapHost .plisle{font-size:7.6px;font-weight:500;font-style:italic;fill:#4A6B4F;stroke-width:2.2px}
#mapHost .plwater{font-size:7.6px;font-weight:500;font-style:italic;fill:#2C6E8F;stroke-width:2.2px}
#mapHost .place{pointer-events:none}
#mapHost .housemark{pointer-events:none}
#mapHost .housetext{font-family:var(--sans);font-size:9px;font-weight:700;fill:#24382A;
  paint-order:stroke fill;stroke:#F6F2E7;stroke-width:3px;stroke-linejoin:round}

/* ---------- fish silhouettes and the species picker ---------- */
/* A drawn silhouette sits next to a traced one in the same grid, so it is painted the
   same way the tracing script paints its outlines: moss at a sixth, ink around the
   edge. Two icon sets in one picker looked like a mistake. The stroke is in viewBox
   units so it thins with the icon, exactly as the traced outlines do. */
.fishicon{fill:rgba(56,82,62,.16);stroke:rgba(28,42,32,.7);stroke-width:1.2;stroke-linejoin:round;
  display:block}
.fishtrace{display:block;object-fit:contain;object-position:center}
.fpcred{margin:12px 2px 2px;font-size:10.5px}

/* ---------- the kookaburra ----------
   Small movements, and most of them rare. A mascot in constant motion stops being
   charming about four seconds in. */
.kooka{display:block}
.kooka .kb-all{transform-origin:60px 100px;animation:kbBreathe 4.2s ease-in-out infinite}
@keyframes kbBreathe{0%,100%{transform:translateY(0) rotate(0deg)}50%{transform:translateY(-1.5px) rotate(-.6deg)}}
/* The lid drops for a tenth of a second every five or so — long enough to notice,
   short enough not to look sleepy. */
.kooka .kb-lid{transform-origin:42px 37.5px;transform:scaleY(0);animation:kbBlink 5.4s ease-in-out infinite}
@keyframes kbBlink{0%,92%,100%{transform:scaleY(0)}95%{transform:scaleY(1)}}
.kooka .kb-tail{transform-origin:72px 94px;animation:kbTail 4.2s ease-in-out infinite}
@keyframes kbTail{0%,100%{transform:rotate(0deg)}50%{transform:rotate(3deg)}}
/* The laugh, for when something has actually gone right. */
.kooka.laugh .kb-all{animation:kbLaugh .9s ease-in-out 2}
@keyframes kbLaugh{0%,100%{transform:rotate(0) translateY(0)}
  25%{transform:rotate(-7deg) translateY(-4px)}
  60%{transform:rotate(5deg) translateY(-1px)}}
.kooka.laugh .kb-beak{transform-origin:30px 48px;animation:kbChatter .18s ease-in-out 9}
@keyframes kbChatter{0%,100%{transform:rotate(0)}50%{transform:rotate(-9deg)}}
@media (prefers-reduced-motion:reduce){
  .kooka .kb-all,.kooka .kb-lid,.kooka .kb-tail,.kooka.laugh .kb-all,.kooka.laugh .kb-beak{animation:none}
  .kooka .kb-lid{transform:scaleY(0)}
}

/* ---------- the tour ---------- */
.tourtop{display:flex;align-items:center;gap:13px;margin-bottom:12px}
.tourtop .kooka{flex:0 0 auto}
.tourtop-t{flex:1;min-width:0}
.tourtop-t h2{margin:0;font-size:20px}
.tourtop-t p{margin:2px 0 0;font-size:12px;color:var(--muted)}
.tourbody{font-size:14.5px;line-height:1.5;margin:0 0 14px}
.tourbody strong{color:var(--moss)}
.tourwhere{display:inline-flex;align-items:center;gap:6px;margin:0 0 12px;padding:5px 11px;
  border-radius:999px;background:var(--paper-2);font-size:11.5px;font-weight:700;
  letter-spacing:.03em;text-transform:uppercase;color:var(--moss)}
.tourwhere svg{width:15px;height:15px;stroke:currentColor;fill:none;stroke-width:1.8;
  stroke-linecap:round;stroke-linejoin:round}

/* ---------- the day switch in Conditions ---------- */
.daychips{display:flex;gap:5px;overflow-x:auto;-webkit-overflow-scrolling:touch;
  margin:0 0 10px;padding-bottom:2px;scrollbar-width:none}
.daychips::-webkit-scrollbar{display:none}
.daychips button{flex:0 0 auto;min-width:52px;padding:6px 9px;border-radius:10px;
  border:1px solid var(--line);background:var(--card);color:var(--moss);text-align:center;line-height:1.15}
.daychips .dc-dow{display:block;font-size:10px;font-weight:700;letter-spacing:.03em;text-transform:uppercase}
.daychips .dc-num{display:block;font-family:var(--serif);font-size:16px;font-weight:600;margin-top:1px}
.daychips button.on{background:var(--moss);border-color:var(--moss);color:var(--paper)}

/* One day's tides, read down rather than across. */
.tideday-list{display:flex;flex-direction:column}
.tdrow{display:flex;align-items:baseline;gap:10px;padding:9px 0;border-bottom:1px solid var(--line)}
.tdrow:last-child{border-bottom:0}
.tdlab{flex:0 0 42px;font-size:11px;font-weight:700;letter-spacing:.04em;text-transform:uppercase}
.tdrow.high .tdlab{color:var(--blue)}
.tdrow.low .tdlab{color:var(--gold-text)}
.tdtime{flex:1;font-family:var(--serif);font-size:19px;font-weight:600;
  font-variant-numeric:tabular-nums;color:var(--ink)}
.tdh{flex:0 0 auto;font-size:13px;color:var(--muted);font-variant-numeric:tabular-nums}

/* ---------- a contact ----------
   Its own card, stacked. The name and what they do get the whole width; the things
   you do with it sit underneath as labelled buttons, where they are readable with wet
   hands and obvious to somebody who has never opened this tab before. */
.contact{border:1px solid var(--line);border-radius:12px;background:var(--card);
  padding:13px 14px;margin-bottom:9px;box-shadow:var(--shadow)}
.contact .ct-name{font-size:15.5px;font-weight:600;line-height:1.25}
.contact .ct-role{font-size:13px;color:var(--moss);margin-top:2px;line-height:1.4}
.contact .hours{margin-top:7px}
.contact-note{margin:7px 0 0;font-size:13px;line-height:1.45;color:var(--muted)}
.contact-note.nonum{color:var(--danger)}
.contact-acts{display:flex;flex-wrap:wrap;gap:7px;margin-top:11px}
.contact-acts .btn{flex:1 1 auto;min-width:88px;padding:8px 12px}
/* Admin controls sit below a rule, out of the content's way — they are housekeeping,
   not part of what the contact says. */
.contact-admin{display:flex;align-items:center;gap:10px;margin-top:11px;
  padding-top:10px;border-top:1px solid var(--line)}
.contact-admin .gtoggle{flex:1;min-width:0}
.contact-admin .ctmove{flex:0 0 auto;flex-direction:row;margin:0}
/* Two subscriptions, offered as two equal choices rather than one headline and one
   afterthought — they answer different questions and people want different ones. */
.feedopt{border:1px solid var(--line);border-radius:12px;padding:13px 14px;
  background:var(--card,var(--card));margin-bottom:10px}
.feedopt h3{margin:0 0 3px;font-size:15.5px}
.feedopt p{margin:0 0 10px;font-size:12.5px;color:var(--muted);line-height:1.45}
/* An invitation addressed to you, at the top of the booking it is about. */
.invite{margin:0 0 14px;padding:14px 15px;border-radius:12px;
  background:var(--gold-pale);border:1px solid var(--gold)}
.invite strong{display:block;font-family:var(--serif);font-size:17px;color:var(--ink)}
.invite p{margin:4px 0 11px;font-size:13.5px;color:var(--ink)}
.invite .btn.ghost{background:transparent;border-color:var(--line);color:var(--ink)}

/* ---------- picking a range on the month ---------- */
.pickbar{display:flex;align-items:center;gap:9px;margin:0 0 10px;padding:10px 12px;
  border-radius:11px;background:var(--deep);color:var(--on-deep);box-shadow:var(--shadow)}
.pickbar-txt{flex:1;min-width:0}
.pickbar-txt strong{display:block;font-size:13.5px;line-height:1.25}
.pickbar-txt em{display:block;font-style:normal;font-size:11.5px;color:var(--gold-on-deep);opacity:.85}
.pickbar .btn{flex:0 0 auto;padding:6px 12px}
.pickbar .btn.ghost{background:transparent;color:var(--gold-on-deep);border-color:rgba(246,242,231,.35)}
/* The ends of the range are solid, the nights between are tinted — the shape of the
   stay is the feedback, so it has to be legible before the second tap lands. */
/* z-index only. Setting position here would override the absolute placement the
   numbers rely on, drop them back into flow, and leave a picked cell twice the height
   of its row — spilling over the week underneath. */
.day.pk .num{z-index:1}
.day.pk::before{content:'';position:absolute;inset:0;z-index:0;background:var(--gold-pale)}
.day.pk-mid::before{background:var(--gold-pale);opacity:.55}
.day.pk-a::before{border-radius:9px 0 0 9px}
.day.pk-b::before{border-radius:0 9px 9px 0}
.day.pk-one::before{border-radius:9px}
.day.pk-a::before,.day.pk-b::before,.day.pk-one::before{background:var(--gold)}
.day.pk-a .num,.day.pk-b .num,.day.pk-one .num{color:var(--gold-ink);font-weight:700}
/* ---------- first-run tutorial ---------- */
.tutdots{display:flex;gap:5px;margin:0 0 14px}
.tutdots span{width:22px;height:4px;border-radius:99px;background:var(--line)}
.tutdots span.on{background:var(--gold)}
.tutdots span.past{background:var(--sage)}
.tutlead{margin:0 0 14px;font-size:14.5px;line-height:1.5;color:var(--ink)}
/* The X on every sheet. Swiping down works, but a swipe is something you have to know
   about and an X is something you can see. */
.sheetx{position:absolute;top:8px;right:10px;z-index:2;width:34px;height:34px;
  border-radius:50%;background:var(--paper-2);color:var(--muted);
  font-size:22px;line-height:1;display:grid;place-items:center}
.sheetx:active{background:var(--line)}

/* ---------- help ---------- */
.helpbtn{flex:0 0 auto;width:30px;height:30px;margin-right:8px;border-radius:50%;
  border:1.5px solid rgba(246,242,231,.4);background:transparent;color:var(--gold-on-deep);
  font-family:var(--serif);font-size:15px;font-weight:700;line-height:1}
.hsearch{margin-bottom:10px}
.hgroup{font-family:var(--serif);font-size:13px;font-weight:600;color:var(--moss);
  margin:14px 0 6px;padding-bottom:4px;border-bottom:1px solid var(--line)}
.hrow{display:flex;align-items:center;gap:10px;width:100%;padding:11px 2px;
  border-bottom:1px solid var(--line);background:none;text-align:left}
.hrow:last-child{border-bottom:0}
.hrow-main{flex:1;min-width:0}
.hrow-t{display:block;font-size:14px;font-weight:600;color:var(--ink)}
.hrow-s{display:block;font-size:11.5px;color:var(--muted);margin-top:1px}
.hrow-go{flex:0 0 auto;color:var(--gold);font-size:19px;line-height:1}
.hbody p{margin:0 0 11px;font-size:14px;line-height:1.5}
.hbody ol,.hbody ul{margin:0 0 12px;padding-left:22px}
.hbody li{margin:0 0 8px;font-size:14px;line-height:1.45}
.hbody strong{font-weight:700;color:var(--ink)}
/* "Why is it like this?" — the box that stops the same question being asked again. */
.hwhy{margin:0 0 12px;padding:11px 13px;border-radius:10px;background:var(--paper-2);
  border-left:3px solid var(--gold)}
.hwhy strong{display:block;font-family:var(--serif);font-size:14px;margin-bottom:3px}
.hwhy p{margin:0;font-size:13.5px;line-height:1.45}
.hwhy p+p{margin-top:8px}
/* The small "how does this work?" links that sit next to the confusing things. */
.hlink{padding:0;background:none;border:0;color:var(--moss);font-size:12px;
  font-weight:600;text-decoration:underline;text-underline-offset:2px}

/* ---------- setup checklist ---------- */
.suprow{display:flex;align-items:center;gap:11px;width:100%;padding:11px 2px;
  border-bottom:1px solid var(--line);background:none;text-align:left}
.suprow:last-child{border-bottom:0}
.sutick{flex:0 0 auto;width:24px;height:24px;border-radius:50%;border:2px solid var(--line);
  display:grid;place-items:center;font-size:13px;font-weight:700;color:transparent}
.suprow.done .sutick{background:var(--moss);border-color:var(--moss);color:var(--paper)}
.sumain{flex:1;min-width:0}
.sutitle{display:block;font-size:14px;font-weight:600;color:var(--ink)}
.sutitle em{font-style:normal;font-weight:500;font-size:11px;color:var(--muted)}
.suprow.done .sutitle{font-weight:500;color:var(--muted)}
.sunote{display:block;font-size:11.5px;color:var(--muted);margin-top:1px}
.sugo{flex:0 0 auto;color:var(--gold);font-size:19px;line-height:1}

/* ---------- shopping list ---------- */
.shrow{display:flex;align-items:flex-start;gap:10px;padding:10px 2px;border-bottom:1px solid var(--line)}
.shrow:last-child{border-bottom:0}
.shrow.off .shtext{text-decoration:line-through;color:var(--muted)}
/* A big circle: this gets tapped with wet hands, standing up, on a boat. */
.shtick{flex:0 0 auto;width:26px;height:26px;margin-top:1px;border-radius:50%;
  border:2px solid var(--sage);background:transparent}
.shtick.on{background:var(--moss);border-color:var(--moss);
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23F6F2E7' stroke-width='3.4' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m5 12.5 4.5 4.5L19 7'/%3E%3C/svg%3E");
  background-size:16px;background-position:center;background-repeat:no-repeat}
.shmain{flex:1;min-width:0;text-align:left;background:none;padding:0}
.shtext{display:block;font-size:14px;line-height:1.35;color:var(--ink)}
.shwho{display:block;margin-top:2px;font-size:11.5px;color:var(--muted)}
.shflag{font-style:normal;font-size:10px;font-weight:700;letter-spacing:.03em;
  text-transform:uppercase;color:var(--danger);margin-right:5px}
.shopchips{margin-bottom:10px}
/* The count on the House tab, so the list is noticed without being opened. */
.tabcount{position:absolute;transform:translate(15px,-6px);min-width:15px;height:15px;
  padding:0 4px;border-radius:999px;background:var(--gold);color:var(--gold-ink);
  font-size:9.5px;font-weight:700;line-height:15px;text-align:center}
.toast-act{margin-left:12px;padding:0;background:none;border:0;color:var(--gold-on-deep);
  font-weight:700;font-size:13px;text-decoration:underline;text-underline-offset:2px}
/* Who's coming: people grouped under the family they belong to, so picking two from
   one branch and one from another is a matter of tapping faces rather than reasoning
   about families at all. */
.ppick{display:flex;flex-direction:column;gap:10px;margin-top:2px}
.ppgroup{}
.ppname{display:flex;align-items:center;gap:6px;margin:0 0 5px;font-size:11.5px;
  font-weight:700;letter-spacing:.02em;text-transform:uppercase;color:var(--muted)}
.ppname .swatch{width:9px;height:9px;min-height:0;border-radius:3px;flex:0 0 auto}
.pprow{display:flex;flex-wrap:wrap;gap:6px}
.pp{display:inline-flex;align-items:center;gap:6px;padding:4px 11px 4px 4px;
  border:1px solid var(--line);border-radius:999px;background:var(--card);
  font-size:12.5px;font-weight:500;color:var(--ink)}
.pp .avatar{flex:0 0 auto}
.pp.on{background:var(--gold-pale);border-color:var(--gold);box-shadow:inset 0 0 0 1px var(--gold)}
.pp.on span{font-weight:700}
/* Whoever books is always on it, so their chip reads as settled rather than tappable. */
.pp.fixed{opacity:.9}
.pp:active{transform:scale(.97)}
/* Numbered how-to steps. Used by every "do this on your phone" sheet, so they are
   roomy enough to follow with the phone in your other hand. */
.steps{margin:0;padding-left:22px}
.steps li{margin:0 0 9px;font-size:14px;line-height:1.45}
.steps li:last-child{margin-bottom:0}
.steps strong{font-weight:700;color:var(--ink)}
/* Markings read as ink on a pale body now — a bar picked out in paper-white vanished
   the moment the body stopped being solid. */
.fishicon .fm-l{fill:var(--ink);stroke:var(--ink);stroke-linecap:round;opacity:.24}
.fishicon .fm-d{fill:var(--ink);stroke:var(--ink);stroke-linecap:round;opacity:.4}
.fishpick{margin-top:2px}
.fpgroup{font-family:var(--serif);font-size:13px;font-weight:600;color:var(--moss);
  margin:12px 0 6px;padding-bottom:4px;border-bottom:1px solid var(--line)}
.fpgroup:first-child{margin-top:4px}
.fpgrid{display:grid;grid-template-columns:repeat(auto-fill,minmax(104px,1fr));gap:6px}
.fptile{display:flex;flex-direction:column;align-items:center;justify-content:flex-start;
  gap:2px;padding:8px 4px 6px;border:1px solid var(--line);border-radius:10px;
  background:var(--card);color:#78876F;text-align:center;min-height:82px;transition:none}
.fptile span{font-size:10.5px;line-height:1.15;color:var(--ink);font-weight:500}
.fptile.on{background:var(--gold-pale);border-color:var(--gold);color:var(--ink);box-shadow:inset 0 0 0 1px var(--gold)}
.fptile.on span{font-weight:700}
.fptile:active{background:var(--paper-2)}
@media (max-width:360px){.fpgrid{grid-template-columns:repeat(auto-fill,minmax(84px,1fr))}}
/* ---------- the pin you just dropped ---------- */
#pinBar{max-height:0;overflow:hidden;transition:max-height .22s ease}
#pinBar.on{max-height:120px}
.pinbar{display:flex;align-items:center;gap:10px;margin:10px 0 2px;padding:10px 12px;
  border:1px solid var(--gold);border-radius:12px;background:var(--gold-pale)}
.pinbar-dot{flex:0 0 auto;width:14px;height:14px;border-radius:50%;background:var(--danger);
  box-shadow:0 0 0 3px rgba(168,69,47,.22)}
.pinbar-txt{flex:1;min-width:0}
.pinbar-txt strong{display:block;font-size:13.5px}
.pinbar-txt em{display:block;font-style:normal;font-size:11.5px;color:#7A6A45;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.pinbar .btn{flex:0 0 auto;padding:6px 12px}

/* ---------- select with a face ---------- */
.isel{position:relative}
.isel-btn,.isel-opt{display:flex;align-items:center;gap:10px;width:100%;text-align:left;
  padding:9px 11px;border:1px solid var(--line);border-radius:var(--r);background:var(--card);color:var(--ink)}
.isel-opt{border:0;border-radius:0;border-bottom:1px solid var(--line);padding:10px 11px}
.isel-opt:last-child{border-bottom:0}
.isel-opt.on{background:var(--gold-pale)}
.isel-opt:active{background:var(--paper-2)}
.isel-text{flex:1;min-width:0}
.isel-label{display:block;font-size:14px;font-weight:600;line-height:1.2;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.isel-sub{display:block;font-size:11.5px;color:var(--ink-3);line-height:1.25;margin-top:1px;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.isel-chev{width:18px;height:18px;flex:0 0 auto;fill:none;stroke:var(--sage);stroke-width:2.2;
  stroke-linecap:round;stroke-linejoin:round;transition:transform .15s}
.isel[data-open="1"] .isel-chev{transform:rotate(180deg)}
.isel[data-open="1"] .isel-btn{border-color:var(--moss)}
.isel-dot{width:22px;height:22px;border-radius:50%;flex:0 0 auto;
  box-shadow:inset 0 0 0 1px rgba(28,42,32,.18)}
.isel-gap{width:22px;flex:0 0 auto}
.isel-list{position:absolute;left:0;right:0;top:calc(100% + 5px);z-index:5;background:var(--card);
  border:1px solid var(--line);border-radius:12px;overflow:hidden auto;max-height:270px;
  box-shadow:0 10px 26px rgba(28,42,32,.16)}
.isel-none{margin:0;padding:14px 12px;font-size:13px;color:var(--ink-3);line-height:1.4}
.isel .avatar{flex:0 0 auto}

/* ---------- colour swatches ---------- */
.swatches{display:grid;grid-template-columns:repeat(auto-fill,minmax(88px,1fr));gap:6px}
.swatch-btn{display:flex;flex-direction:column;align-items:center;gap:5px;padding:9px 4px 7px;
  border:1px solid var(--line);border-radius:10px;background:var(--card)}
.sw{width:30px;height:30px;border-radius:50%;display:block;position:relative;
  box-shadow:inset 0 0 0 1px rgba(28,42,32,.16)}
.swname{font-size:10.5px;font-weight:500;color:var(--ink-3);line-height:1.15;text-align:center}
.swatch-btn.on{border-color:var(--moss);background:var(--paper-2);box-shadow:inset 0 0 0 1px var(--moss)}
.swatch-btn.on .swname{color:var(--ink);font-weight:700}
/* A tick, so the choice doesn't rest on the border alone — that is invisible to
   anyone who can't separate the two colours it sits between. */
.swatch-btn.on .sw::after{content:'';position:absolute;left:9px;top:6px;width:8px;height:14px;
  border:solid var(--paper);border-width:0 2.5px 2.5px 0;transform:rotate(42deg);
  filter:drop-shadow(0 0 1px rgba(0,0,0,.45))}
.swatch-btn:active{background:var(--paper-2)}

/* ---------- notification switches ---------- */
.nrow{display:flex;align-items:center;gap:12px;width:100%;text-align:left;padding:11px 0;
  border-bottom:1px solid var(--line);background:none}
.nrow:last-of-type{border-bottom:0}
.nrow-main{flex:1;min-width:0}
.nrow-title{display:block;font-size:14px;font-weight:600;color:var(--ink)}
.nrow-note{display:block;font-size:12px;color:var(--ink-3);margin-top:1px;line-height:1.35}
.nsw{flex:0 0 auto;width:44px;height:26px;border-radius:99px;background:var(--line);position:relative;
  transition:background .16s}
.nsw i{position:absolute;top:3px;left:3px;width:20px;height:20px;border-radius:50%;background:#fff;
  transition:transform .16s;box-shadow:0 1px 2px rgba(28,42,32,.25)}
.nsw.on{background:var(--moss)}
.nsw.on i{transform:translateX(18px)}
.nlead{display:flex;align-items:center;gap:10px;padding:8px 0 11px;border-bottom:1px solid var(--line)}
.nlead label{flex:1;font-size:13px;color:var(--ink-3)}
.nlead select{width:auto;padding:6px 10px}
.nlead.off{opacity:.4;pointer-events:none}

/* ---------- hour by hour ---------- */
.hourly{display:flex;gap:2px;overflow-x:auto;-webkit-overflow-scrolling:touch;padding-bottom:4px;
  scroll-snap-type:x proximity}
.hr{flex:0 0 auto;width:46px;display:flex;flex-direction:column;align-items:center;gap:3px;
  padding:6px 2px;border-radius:9px;scroll-snap-align:start}
.hr.night{background:var(--paper-2)}
.hr.now{background:var(--gold-pale);box-shadow:inset 0 0 0 1px var(--gold)}
.hrt{font-size:10.5px;font-weight:700;color:var(--ink-3)}
.hr.now .hrt{color:var(--ink)}
.hrsym{width:19px;height:19px;color:var(--moss);display:block}
.hrsym svg{width:19px;height:19px}
.hrbarwrap{height:30px;display:flex;align-items:flex-end}
.hrbar{display:block;width:5px;border-radius:3px;background:linear-gradient(180deg,var(--gold),var(--sage))}
.hrdeg{font-family:var(--serif);font-size:13.5px;font-weight:600}
.hrwind{font-size:10.5px;color:var(--ink-3);line-height:1}
.hrwind em{font-style:normal;font-size:8px}
.hrarrow{font-size:12px;line-height:1;color:var(--blue);display:block}
.hrrain{font-size:9.5px;color:var(--ink-3)}
.hrrain.wet{color:var(--blue);font-weight:700}

/* ---------- PIN keypad ---------- */
.pinbox{margin:6px 0 4px}
.pinbox:focus{outline:none}
.pinlabel{font-size:13px;text-align:center;margin:0 0 10px;opacity:.85}
.pindots{display:flex;justify-content:center;gap:16px;margin-bottom:6px}
.pindots i{width:14px;height:14px;border-radius:50%;border:1.6px solid currentColor;opacity:.5;transition:opacity .12s,background .12s}
.pindots i.on{background:currentColor;opacity:1}
.pinerr{min-height:17px;font-size:12.5px;text-align:center;margin:0 0 8px;color:var(--danger)}
.pindots i{color:var(--moss)}
.pinkeys{display:grid;grid-template-columns:repeat(3,1fr);gap:10px;max-width:300px;margin:0 auto}
.pinkeys button{height:60px;border-radius:14px;border:1px solid var(--line);background:var(--card);
  color:var(--ink);font-family:var(--serif);font-size:25px;font-weight:600;
  box-shadow:0 1px 0 rgba(28,42,32,.05)}
.pinkeys button:active{background:var(--paper-2);box-shadow:none}
.pinkeys .pinghost{background:none;border-color:transparent;box-shadow:none;color:var(--moss);
  font-family:var(--sans);font-size:13px;font-weight:600}
.pinkeys .pinghost svg{width:26px;height:26px;fill:none;stroke:currentColor;stroke-width:1.7;stroke-linecap:round;stroke-linejoin:round}
.shake{animation:shake .38s}
@keyframes shake{10%,90%{transform:translateX(-2px)}20%,80%{transform:translateX(4px)}30%,50%,70%{transform:translateX(-7px)}40%,60%{transform:translateX(7px)}}

/* ---------- family branch view ---------- */
.statrow{display:grid;grid-template-columns:repeat(3,1fr);gap:8px;margin:12px 0 4px}
.stat{background:var(--card);border:1px solid var(--line);border-radius:var(--r);padding:10px 8px;
  text-align:center;font-size:11px;color:var(--ink-3);line-height:1.3}
.stat span{display:block;font-family:var(--serif);font-size:21px;font-weight:600;color:var(--ink)}
.famrow{display:flex;flex-wrap:wrap;gap:6px;margin-top:10px}
.fammember{display:inline-flex;align-items:center;gap:5px;padding:3px 9px 3px 3px;border-radius:999px;
  background:var(--paper-2);font-size:12px;font-weight:500}

.fpsearch{display:flex;gap:6px;margin:2px 0 4px}
.fpsearch input{flex:1;min-width:0}
.fpaz{flex:0 0 auto;padding:0 14px;border:1px solid var(--line);border-radius:var(--r);
  background:var(--card);font-size:13px;font-weight:600;color:var(--moss)}
.fpaz.on{background:var(--moss);border-color:var(--moss);color:var(--paper)}
.fishpickwrap{position:relative;padding-right:22px}
.azrail{position:absolute;top:44px;right:0;bottom:0;display:flex;flex-direction:column;
  justify-content:flex-start;gap:0;width:20px;overflow:hidden}
.azrail button{font-size:9.5px;line-height:1.18;font-weight:700;color:var(--muted);
  padding:0;background:none;border:0}
.azrail button:active{color:var(--gold)}
.fpnone{font-size:13px;color:var(--ink-3);padding:14px 4px;line-height:1.45}
.fptile.notake{border-color:var(--danger-pale);background:var(--danger-pale);color:#A88B84}
.fptile.notake .ntflag{display:block;font-size:9px;font-style:normal;font-weight:700;
  letter-spacing:.04em;text-transform:uppercase;color:var(--danger);margin-top:1px}
.fptile.notake.on{background:var(--gold-pale);border-color:var(--gold)}
.notake-note{border-left-color:var(--danger)}

/* ---------- contacts: order and guest visibility ---------- */
.ctmove{display:flex;flex-direction:column;gap:2px;flex:0 0 auto;margin-right:2px}
.ctmove button{width:26px;height:22px;display:flex;align-items:center;justify-content:center;
  border:1px solid var(--line);border-radius:6px;background:var(--card);color:var(--moss)}
.ctmove button svg{width:14px;height:14px;fill:none;stroke:currentColor;stroke-width:2.2;stroke-linecap:round;stroke-linejoin:round}
.ctmove button:disabled{opacity:.3}
.ctmove button:active:not(:disabled){background:var(--paper-2)}
.gtoggle{display:inline-flex;align-items:center;gap:6px;margin-top:6px;padding:3px 8px 3px 3px;
  border:1px solid var(--line);border-radius:999px;background:var(--card);font-size:11px;color:var(--ink-3)}
.gtoggle i{width:26px;height:15px;border-radius:999px;background:var(--line);position:relative;transition:background .15s}
.gtoggle i::after{content:'';position:absolute;top:2px;left:2px;width:11px;height:11px;border-radius:50%;
  background:var(--card);transition:transform .15s}
.gtoggle.on{color:var(--ink);border-color:var(--muted)}
.gtoggle.on i{background:var(--moss)}
.gtoggle.on i::after{transform:translateX(11px)}

/* ---------- Australian date field ---------- */
.dwrap{position:relative;display:flex;align-items:stretch}
.dtext{flex:1;min-width:0}
.dtext.bad{border-color:var(--danger);background:var(--danger-pale)}
/* The real date input sits invisibly ON TOP of the calendar button, rather than being
   hidden away and poked with showPicker(). showPicker throws for an element that isn't
   properly rendered, and .click() does nothing to something with pointer-events:none —
   which is why the button did nothing at all. Tapping the input itself is what opens
   the OS picker, on every browser, with no script involved. */
.dbtnwrap{position:relative;flex:0 0 auto;margin-left:6px;width:46px}
.dnative{position:absolute;inset:0;width:100%;height:100%;opacity:0;margin:0;padding:0;border:0;
  background:none;cursor:pointer;z-index:2;-webkit-appearance:none;appearance:none;
  font-size:16px;/* under 16px iOS zooms the page when it focuses */}
.dbtn{display:flex;align-items:center;justify-content:center;width:46px;height:100%;
  border:1px solid var(--line);border-radius:var(--r);background:var(--card);color:var(--moss)}
.dbtnwrap:focus-within .dbtn{border-color:var(--blue);box-shadow:0 0 0 2px rgba(44,110,143,.18)}
.dbtn svg{width:20px;height:20px;fill:none;stroke:currentColor;stroke-width:1.6;stroke-linecap:round;stroke-linejoin:round}
.dbtn:active{background:var(--paper-2)}

.bkwrap{border-bottom:1px solid var(--line)}
.bkwrap:last-child{border-bottom:0}
.bkwrap .bk{border-bottom:0}
.bkacts{display:flex;gap:6px;padding:0 0 10px 30px}
.bkacts .btn{flex:0 0 auto;padding:5px 12px}
.btn.danger-t{color:var(--danger);border-color:var(--danger-pale)}

.mapcred{font-size:11px;color:var(--ink-3);margin:6px 2px 10px;line-height:1.35}
.mapcred a{color:var(--blue)}
.thumb .fishicon,.photoslot .fishicon,.photobig .fishicon{opacity:.65}
.dropped{animation:drop .25s ease-out}
@keyframes drop{from{transform:translateY(-8px);opacity:0}}
.mapctl{position:absolute;right:8px;top:8px;display:flex;flex-direction:column;gap:6px}
.mapctl button{width:36px;height:36px;border-radius:9px;background:rgba(246,242,231,.94);
  border:1px solid var(--line);color:var(--moss);display:grid;place-items:center;box-shadow:var(--shadow)}
.chips{display:flex;flex-wrap:wrap;gap:6px;margin-top:10px;align-items:center}
.chips button{padding:6px 12px;border-radius:99px;border:1px solid var(--line);background:var(--card);
  font-size:12.5px;font-weight:600;color:var(--moss)}
.chips button.on{background:var(--moss);border-color:var(--moss);color:var(--paper)}
.chips select{width:auto;padding:6px 10px;border-radius:99px;font-size:12.5px;font-weight:600}
.thumb{width:46px;height:46px;border-radius:9px;background:var(--paper-2);color:var(--muted);
  display:grid;place-items:center;overflow:hidden;flex:0 0 auto}
.thumb img{width:100%;height:100%;object-fit:cover;display:block}
.thumb .ic{width:20px;height:20px}
.photobig{width:100%;aspect-ratio:4/3;border-radius:12px;background:var(--paper-2);color:var(--muted);
  display:grid;place-items:center;overflow:hidden}
.photobig img{width:100%;height:100%;object-fit:cover;display:block}
.photobig .ic{width:38px;height:38px}
/* A photo of a catch fills its tile; a traced outline is an icon standing in for one
   that has no photo, so it is fitted whole and inset. Without this the cover rule
   above wins on specificity and crops every fish into a square. */
.thumb img.fishtrace,.photobig img.fishtrace,.photoslot img.fishtrace{
  width:auto;height:auto;max-width:84%;max-height:84%;object-fit:contain}
.photorow{display:flex;gap:10px;align-items:center}
.photoslot{width:56px;height:56px;border-radius:10px;background:var(--paper-2);color:var(--muted);
  display:grid;place-items:center;overflow:hidden;flex:0 0 auto}
.photoslot img{width:100%;height:100%;object-fit:cover}
.rank{width:22px;text-align:center;font-family:var(--serif);font-size:16px;font-weight:600;
  color:var(--muted);flex:0 0 auto}
.rank.gold{color:var(--gold)}
.bignum{font-family:var(--serif);font-size:21px;font-weight:600;color:var(--moss);flex:0 0 auto}
.bignum em{font-style:normal;font-size:11px;color:var(--muted);margin-left:1px}
.tabs.six .tab{font-size:9.5px}
.tabs.six .tab svg{width:20px;height:20px}

/* ---------- things the restructure added ---------- */
[hidden]{display:none!important}
#app[inert]{pointer-events:none;user-select:none}
.banner{display:flex;align-items:center;gap:10px;padding:8px 15px;font-size:var(--t-s);background:var(--gold-pale);color:var(--ink);flex:0 0 auto}
.banner.off{background:var(--danger-pale)}
.banner b{font-weight:600}
.sk{background:var(--skeleton);background-size:200% 100%;animation:sk 1.2s linear infinite;border-radius:6px;color:transparent!important}
.sk.line{height:14px;margin:8px 0}.sk.line.w60{width:60%}.sk.line.w40{width:40%}.sk.block{height:120px;border-radius:14px}
@keyframes sk{from{background-position:200% 0}to{background-position:-200% 0}}
.adsec[hidden]{display:none}
.seg.adtabs{display:flex;width:100%;margin-bottom:14px}.seg.adtabs button{flex:1}
.since{border-color:var(--gold)}
.since .ct-role{color:var(--ink-2)}
.theme-seg{display:inline-flex;background:var(--paper-2);border-radius:999px;padding:3px;gap:2px}
.theme-seg button{padding:6px 14px;border-radius:999px;font-size:var(--t-s);font-weight:600;color:var(--ink-3)}
.theme-seg button.on{background:var(--card);color:var(--ink);box-shadow:var(--shadow)}
.sysdark .bi,:root[data-theme="dark"] .bi{filter:invert(.85)}
/* The fish are traced in ink on a clear ground; at night the ink goes pale. */
.sysdark .fishtrace,:root[data-theme="dark"] .fishtrace{filter:invert(.88) hue-rotate(180deg)}
:root[data-theme="light"] .bi,:root[data-theme="light"] .fishtrace{filter:none}
.sysdark .topmark,:root[data-theme="dark"] .topmark{filter:none}
