/* ob-site.css — page-specific layout for the doc-097 landing pages
   (Home / Local / Travel / Stock).

   Tokens, header, drawer, buttons, badges and the bottom nav moved to
   ob-shell.css, which the app shares — load ob-shell.css BEFORE this file.
   What is left here is only what these four documents draw and the app does
   not. High-fidelity to the owner's mockups 31-07-2026. */

/* ---------- generic ---------- */
.wrap{padding:12px 14px}
.sectit{font-size:19px;font-weight:700;color:var(--ink);margin:16px 14px 6px}
.pagetit{font-size:30px;font-weight:700;color:var(--ink);margin:10px 14px 2px;line-height:1.08}
.pagesub{font-size:13.5px;color:var(--body);margin:4px 14px 2px;line-height:1.4}
.stale{font-size:12.5px;color:var(--mut);margin:0 16px 6px}

/* ---------- disclosure rows: the travel page's three cards ----------
   Owner 08-08: "the size is all over the place and I like it when it's
   consistent." Every row in every card is now the SAME bar height and the
   detail lives behind a native <details>, so a card reads as a stack of equal
   bars until you open one.

   Native <details>/<summary> rather than a JS toggle, for the same reason the
   rest of these pages degrade cleanly: with scripting off the rows still open
   and no fact is lost. `name` on the details makes each card an exclusive
   accordion where the browser supports it (Chrome 120+, Safari 17.2+), so the
   card grows by one detail at most; older browsers just allow several open.
   Rows with nothing to add are .static — same bar, no chevron, nothing to tap. */
.flist,.steps{background:var(--card);border:1.5px solid var(--line);border-radius:var(--r);padding:0 13px}
.flist{margin:12px 14px}
.steps{margin:8px 14px 0}
.flist .frow,.steps .step{border-bottom:1px solid #e8edf5}
.flist .frow:last-child,.steps .step:last-child{border-bottom:0}

/* THE BAR. One min-height for every row in both cards; the summary and the
   static row are the same box so an un-openable row never sits a pixel off. */
.flist .frow>summary,.flist .frow.static,
.steps .step>summary,.steps .step.static{
  display:flex;align-items:center;gap:12px;min-height:56px;padding:6px 2px;
  list-style:none;cursor:pointer;-webkit-tap-highlight-color:transparent}
.flist .frow.static,.steps .step.static{cursor:default}
/* Safari/Chrome still paint the default triangle without this */
.flist .frow>summary::-webkit-details-marker,
.steps .step>summary::-webkit-details-marker{display:none}
.flist .frow>summary::marker,.steps .step>summary::marker{content:""}
.flist .frow>summary:focus-visible,.steps .step>summary:focus-visible{
  outline:2px solid var(--ink);outline-offset:-3px;border-radius:8px}

/* the row's own furniture */
.flist .ic{flex:0 0 28px;color:var(--ink);display:flex}
.flist .ic svg{width:26px;height:26px}
.steps .n{flex:0 0 28px;height:28px;border-radius:50%;background:var(--ink);color:#fff;
  display:flex;align-items:center;justify-content:center;font-weight:700;font-size:13.5px}
.steps .ic{flex:0 0 30px;color:var(--ink);display:flex}
.steps .ic svg{width:28px;height:28px}
/* the one-line title. Titles are written to FIT one line at 320px — if one ever
   wraps the bars stop being equal, which is the whole point of this component. */
.flist .ft,.steps summary b,.steps .static b{
  flex:1;min-width:0;margin:0;font-size:14px;font-weight:600;color:var(--ink);line-height:1.25}
.steps summary b,.steps .static b{font-weight:700}
.flist .ft span,.steps b span{font-size:inherit;font-weight:inherit;color:inherit}
.chev{flex:0 0 15px;width:15px;height:15px;color:var(--mut);transition:transform .18s ease-out}
[open]>summary .chev{transform:rotate(180deg)}

/* the detail. Indented to the title column in .flist; in .steps the number and
   the icon together are too wide to clear, so it sits under the icon instead. */
.flist .frow>p,.steps .step>p{margin:-2px 0 0;padding:0 2px 12px 40px;
  font-size:12.5px;color:var(--body);line-height:1.42}
.flist .frow>p a{color:var(--ink);font-weight:600}
.flist .frow>p b,.steps .step>p b{color:var(--ink);font-weight:700}

/* the hold row: an "i" in place of the step number, and a rule above it so it
   reads as a standing condition rather than a fifth thing that happens last.
   Owner 08-08: it used to be a cyan (--gilt) disc, which was the only cyan on
   the page and broke the theme — same navy disc as the numbers, marked by the
   glyph rather than by colour. */
.steps .step.clock{border-top:1.5px solid var(--line);border-bottom:0}
.steps .step.clock .n{font-size:15.5px;line-height:1}

/* ======================================================================
   LOCAL PAGE (ocean-basket-local.html) — doc-097 polish round
   Tab rail + lesson panel, then the collection-point picker synced to the
   Mahé map. All classes below are used by this page only.
   ====================================================================== */

/* ---------- information about buying: tab rail + lesson panel ---------- */
.ibuy{display:grid;grid-template-columns:37% 1fr;margin:8px 14px 0;background:var(--card);
  border:1.5px solid var(--line);border-radius:var(--r);overflow:hidden}
.ibrail{display:flex;flex-direction:column;gap:4px;padding:9px;background:var(--tint2);border-right:1.5px solid var(--line)}
.ibtab{display:block;text-align:left;font-family:var(--sans);font-size:12.5px;font-weight:600;color:var(--body);
  background:none;border:0;border-radius:9px;padding:0 11px;min-height:44px;cursor:pointer;line-height:1.25;
  transition:background .15s ease-out,color .15s ease-out}
.ibtab:hover{background:#e2eaf6}
.ibtab.on{background:var(--ink);color:#fff}
/* every panel sits on the same grid cell, so the card's height is the tallest
   panel's height and never moves when the tab changes (owner circled this) */
.ibpanels{display:grid}
/* Owner 07-08 (doc 100 / G8): "I don't like that the space is wasted here."
   The card's height is set by the rail — five 44px touch targets, 254px, and
   44px is the accessibility floor so the rail cannot get shorter. The panels
   were centred inside that, so a short lesson (Same-day is 106px of content)
   floated in the middle with ~148px of blank split above and below it, which
   is what reads as waste.
   The fix is a defined rhythm rather than padding: lead and body top-aligned so
   every tab starts on the same baseline, and the quiet footnote pushed to the
   BOTTOM of the box. Content then occupies both ends by construction and the
   card looks composed at whatever height the rail dictates. */
.ibp{grid-area:1/1;display:flex;flex-direction:column;justify-content:flex-start;padding:14px 15px;
  opacity:0;transform:translateY(5px);pointer-events:none;
  transition:opacity .2s ease-out,transform .2s ease-out}
.ibp.on{opacity:1;transform:none;pointer-events:auto}
/* the lesson gets a mark of its own — one icon per lesson, from the same set as
   the rest of the app (doc 100 / G2), so the component reads as designed rather
   than as text floating in a box */
.ibp b{display:flex;align-items:center;gap:7px;font-size:15px;color:var(--ink);font-weight:700;line-height:1.15}
.ibp b .ibico{flex:0 0 19px;width:19px;height:19px;color:var(--ink)}
/* the spare height goes into legibility, not padding: this card is the page the
   owner called "the make or break of the first few pages", and 12.5px body on a
   phone was the smallest type on it */
.ibp p{margin:7px 0 0;font-size:13.5px;color:var(--body);line-height:1.5}
/* the hydrated value span (data-cfg) must stay inline — same trap the old
   .fcard block had a rule for; nothing here may make a nested span a block */
.ibp p span{display:inline;font-size:inherit;color:inherit}
.ibp p.cutline{margin-top:auto;padding-top:8px;border-top:1px dashed #c9d6e6;font-size:11.5px;color:var(--mut)}

/* the one staggered reveal on this page: the rail wakes first, then the panel —
   a whisper (5px, 220ms), and only for people who haven't asked for less motion */
@media (prefers-reduced-motion:no-preference){
  .ibtab{animation:obwake .22s ease-out backwards}
  .ibtab:nth-child(2){animation-delay:.045s}
  .ibtab:nth-child(3){animation-delay:.09s}
  .ibtab:nth-child(4){animation-delay:.135s}
  .ibtab:nth-child(5){animation-delay:.18s}
  .ibpanels{animation:obwake .22s ease-out .12s backwards}
}
@keyframes obwake{from{opacity:0;transform:translateY(5px)}}

/* ---------- two-col: map + picker ---------- */
/* stretch: the map panel sets the row height, the picker centres beside it.
   Owner 08-08: map on the LEFT, list on the right — most people are
   right-handed and the thumb lands on the thing you scroll. The map is the
   1fr track so every spare pixel goes to it; the picker keeps a 158px floor
   so "STC Victoria" plus its pin icon sits on one line with air around it
   (the hours string that used to set this floor left with the T2 slim-down). */
/* ONE connected widget (owner 18-08): the map and the picker share a single
   card — one outline, one radius, a hairline seam between them. The page
   gutter moved from padding to margin so the card's border can hug both. */
.twocol{display:grid;grid-template-columns:1fr minmax(158px,45%);gap:0;margin:8px 14px 0;align-items:stretch;
  border:1.5px solid var(--line);border-radius:12px;background:var(--card);overflow:hidden}
/* height tracks the width the map actually got, so a 320px phone doesn't get a
   tall column of empty blue beside a shrunken island. 375px and up clamps to 300 */
.mappanel{background:#cfe6f8;border-radius:0;border-right:1px solid var(--line);position:relative;min-height:clamp(240px,80vw,300px);height:100%;overflow:hidden}
.mappanel svg{position:absolute;inset:0;width:100%;height:100%}
.pinlab{font-family:var(--sans);font-weight:600;font-size:11.5px;fill:var(--ink)}
/* map sync: the picked point's pin grows from its tip and gets a ground halo,
   the rest step back. Classes are painted by the page script. */
.mappanel .pin .pinb{transform-box:fill-box;transform-origin:50% 100%;
  transition:transform .2s ease-out,opacity .2s ease-out}
.mappanel .pin.on .pinb{transform:scale(1.16)}
.mappanel .pin.dim .pinb{opacity:.42}
.mappanel .halo{fill:var(--ink);opacity:0;transition:opacity .2s ease-out}
.mappanel .pin.on .halo{opacity:.16}
.mappanel .pinlab{transition:opacity .2s ease-out}
.mappanel .pinlab.on{font-weight:700}
.mappanel .pinlab.dim{opacity:.55}

/* ---------- collection-point picker (drum: half / active / half) ---------- */
/* the card stretches to the map panel's full height (owner 04-08: "these 2
   components the same height"): the drum window centres in the spare space and
   the hint sits at the card's foot */
.pickside{display:flex;flex-direction:column;min-width:0}
.pickcard{--pkh:46px;--pkw:138px; /* row height; window = exactly 3 rows, so the
  active row always shows one FULL neighbour above and below — the barrel feel
  the owner asked for (18-08). Rows are icon + name (+ a call glyph), so 46px
  carries them. The card chrome moved up to .twocol — one connected widget. */
  flex:1;display:flex;flex-direction:column;
  background:var(--card);border:0;border-radius:0;overflow:hidden}
.pickmid{flex:1;display:flex;flex-direction:column;justify-content:center;min-height:var(--pkw)}
.pickdrum{position:relative;height:var(--pkw)}
/* the lens: a quiet band marking where "active" lives */
.picklane{position:absolute;left:6px;right:6px;top:calc((var(--pkw) - var(--pkh))/2);height:var(--pkh);
  background:var(--tint2);border-radius:9px;pointer-events:none}
.pickwin{position:relative;height:var(--pkw);overflow-y:auto;scroll-snap-type:y mandatory;
  scrollbar-width:none;-webkit-overflow-scrolling:touch;outline-offset:-2px}
.pickwin::-webkit-scrollbar{display:none}
.pkpad{height:calc((var(--pkw) - var(--pkh))/2)} /* no-JS fallback only — the picker JS removes these */
.pk{height:var(--pkh);scroll-snap-align:center;display:flex;flex-direction:row;align-items:center;
  gap:9px;padding:0 12px;cursor:pointer;opacity:.6;transform:scale(.97);
  transition:opacity .18s ease-out,transform .18s ease-out}
.pk.on{opacity:1;transform:none}
.pk .pkic{flex:0 0 auto;display:flex;align-items:center}
.pk .pkic svg{width:16px;height:16px;fill:none;stroke:var(--mut);stroke-width:1.8;
  stroke-linecap:round;stroke-linejoin:round}
.pk.on .pkic svg{stroke:var(--ink)}
.pk b{font-size:14px;color:var(--ink);font-weight:700;line-height:1.2;white-space:nowrap;
  overflow:hidden;text-overflow:ellipsis}
.pk .place{font-style:normal;font-weight:500;font-size:11.5px;color:var(--mut);margin-left:2px}
/* tap-to-call, back by owner request (18-08) as a GLYPH, not a number line —
   pinned to the row's end, its own tap target, never selects the row */
.pk .pkcall{flex:0 0 auto;margin-left:auto;display:flex;align-items:center;justify-content:center;
  width:30px;height:30px;border-radius:50%;background:var(--tint,#e9f1fa);color:var(--ink)}
.pk .pkcall svg{width:14px;height:14px;fill:none;stroke:currentColor;stroke-width:1.8;
  stroke-linecap:round;stroke-linejoin:round}
.pk.on .pkcall{background:var(--badge,#e5f5f8)}
/* roll-off fades above and below the lens — they hug the drum, not the card */
/* 12px, not the old 32px: rows are 46px now and a 32px fade buried two thirds
   of each neighbour — the exact rows the 3-row window exists to show */
.pickdrum::before,.pickdrum::after{content:"";position:absolute;left:0;right:0;height:12px;pointer-events:none;z-index:2}
.pickdrum::before{top:0;background:linear-gradient(#fff,rgba(255,255,255,0))}
.pickdrum::after{bottom:0;background:linear-gradient(rgba(255,255,255,0),#fff)}
.pickhint{font-size:11.5px;color:var(--mut);margin:0;padding:0 12px 10px;text-align:center;line-height:1.35}

/* the "Go Fishing" CTA — the page's one loud element (owner 04-08: mid-page,
   "make it stand out nicely, at the bottom it's too dim") */
.btn.go{margin:16px 14px;padding:16px 18px;font-size:16px;border-radius:12px;gap:10px;
  background:linear-gradient(135deg,var(--ink2) 0%,var(--ink) 62%);
  box-shadow:0 6px 18px rgba(20,34,78,.25)}
.btn.go svg{width:22px;height:22px}
.btn.go:active{transform:translateY(1px);box-shadow:0 3px 10px rgba(20,34,78,.22)}

/* reduced motion: same states, no glide — the picker stays fully usable */
@media (prefers-reduced-motion:reduce){
  .ibtab,.ibp,.pk,.mappanel .pin .pinb,.mappanel .halo,.mappanel .pinlab{transition:none}
}

/* visually-hidden live status for the stock search (board itself is not live) */
.vh{position:absolute;width:1px;height:1px;margin:-1px;padding:0;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap;border:0}

/* ---------- stock page ---------- */
/* Search-first (owner 03-08: the full dump was information overload) — a
   search card up top, then one flat card per shop. Shops render header-only
   until a query is typed; the page script draws .srow rows into each .shopcard
   while it matches. Still no chips, suggestions or accordion. */
.ssearch{display:flex;align-items:center;gap:9px;background:var(--card);border:1.5px solid var(--line);
  border-radius:var(--r);margin:8px 14px 0;padding:2px 4px 2px 13px;min-height:48px}
.ssearch[hidden]{display:none}
.ssearch>svg{width:20px;height:20px;color:var(--mut);flex:0 0 auto}
/* 16px is load-bearing: anything smaller makes iOS zoom the page on focus */
.ssearch input{flex:1;min-width:0;min-height:44px;border:0;background:none;outline:none;
  font-family:var(--sans);font-size:16px;color:var(--ink)}
.ssearch input::placeholder{color:var(--mut)}
/* the page draws its own clear button — hide the UA's duplicate cancel-x */
.ssearch input::-webkit-search-cancel-button,.ssearch input::-webkit-search-decoration{-webkit-appearance:none;appearance:none}
.ssearch .qclear{flex:0 0 auto;display:flex;align-items:center;justify-content:center;width:44px;height:44px;
  border:0;background:none;color:var(--mut);cursor:pointer;border-radius:9px}
.ssearch .qclear[hidden]{display:none}
.ssearch .qclear svg{width:15px;height:15px}
/* the teach line under the search field — empty state only, script-toggled */
.shint{font-size:12.5px;color:var(--mut);margin:6px 16px 0;line-height:1.4}
.stocklist{display:flex;flex-direction:column;gap:9px;margin:8px 14px 0}
.shopcard{background:var(--card);border:1.5px solid var(--line);border-radius:var(--r);padding:2px 13px 4px}
.shophead{display:flex;align-items:center;gap:10px;padding:11px 2px 9px}
.shophead svg{width:24px;height:24px;color:var(--ink);flex:0 0 auto}
.shophead b{font-size:15px;font-weight:700;color:var(--ink);line-height:1.25}
.shophead .stamp{margin-left:auto;font-size:11.5px;color:var(--mut);text-align:right;line-height:1.3}
/* rows divide with the same hairline as .flist .frow; border-top so the header
   gets a rule too and the last row closes clean without a :last-child reset */
.srow{display:flex;align-items:center;gap:10px;padding:9px 2px;border-top:1px solid #e8edf5}
.srow .sname{flex:1;font-size:13px;font-weight:600;color:var(--ink);line-height:1.3}
.srow .skg{font-size:12.5px;color:var(--body);font-variant-numeric:tabular-nums}
.srow .badge{flex:0 0 auto}
/* a shop with nothing to show says so honestly, in the same row voice */
.srow.empty{font-size:12.5px;color:var(--mut)}
/* Fourth badge state, alongside ok/warn/bad in ob-shell.css: a count too old to
   stand behind is not "Available" in any colour, so it gets no signal colour. */
.badge.neutral{background:#eef1f6;color:var(--mut);border:1px solid var(--line)}
/* entrance: the same whisper stagger language as local's tab rail (obwake is
   defined above) — the search card wakes with the shops */
@media (prefers-reduced-motion:no-preference){
  .ssearch,.shopcard{animation:obwake .22s ease-out backwards}
  .shopcard:nth-of-type(2){animation-delay:.05s}
  .shopcard:nth-of-type(3){animation-delay:.1s}
  .shopcard:nth-of-type(4){animation-delay:.15s}
  .shopcard:nth-of-type(5){animation-delay:.2s}
}
/* the stagger is an entrance, not a search effect: the page script marks the
   list `settled` on the first keystroke so as-you-type re-renders don't replay
   it. */
.stocklist.settled .shopcard{animation:none}

/* ---------- info note ---------- */
.note{display:flex;gap:10px;background:var(--tint);border-radius:11px;margin:10px 14px 0;
  padding:11px 12px;font-size:12.5px;color:var(--ink);line-height:1.45}
.note .i{flex:0 0 26px;height:26px;border-radius:50%;background:var(--ink);color:#fff;display:flex;align-items:center;justify-content:center;font-weight:700;font-size:14px;font-style:normal}
.note a{color:var(--ink);font-weight:700}

/* ---------- page-title art (local/travel/stock) ---------- */
/* The mockup bled a photo to the right edge, rounded on the left. The art is
   now a product shot on white, and `cover` cropped the Ocean Basket branding
   clean off the side of the Travel Box — the one thing the picture is there to
   show. `contain` keeps the whole object; its white ground sits close enough to
   --page that it reads as floating rather than letterboxed, so the rounding is
   dropped too (there is no longer a visible edge to round). */
.titlerow{display:flex;align-items:flex-start;gap:6px}
.titlerow .tcol{flex:1 1 50%;padding-left:2px}
/* Height comes from the art's own aspect at half-width, rather than a fixed
   box: a fixed box plus `contain` left 50px of dead space above and below the
   Travel Box before the feature list. */
.titlerow .tart{flex:1 1 50%;margin:6px 0 0 0}
.titlerow .tart img{display:block;width:100%;height:auto}

/* Page transitions removed 07-08 (owner: the card→page morph only works when it's
   perfect, and it wasn't) — navigation between the landing pages is a plain load. */

/* ==== BEGIN OB-PREMISE (doc-098) ====
   Home only. States the operating model before the three route cards: this app
   sells one real fish at a time, and picking one takes it off sale. Everything
   else about the app (the hold, the countdown, the single extension) only makes
   sense once the reader has this. Sits between hero and cards; it is a <div>, so
   the cards' a:nth-of-type() entrance stagger is untouched. */
.premise{background:var(--tint2);border:1.5px solid var(--line);border-radius:var(--r);
  margin:14px 14px 2px;padding:12px 14px}
.premise h2{margin:0 0 4px;font-size:15px;font-weight:700;color:var(--ink);line-height:1.2}
.premise p{margin:0;font-size:13.5px;font-weight:500;color:var(--body);line-height:1.4}
body.home .premise{animation:ob-home-in .22s ease-out backwards;animation-delay:.08s}
@media (prefers-reduced-motion:reduce){ body.home .premise{animation:none} }
/* ==== END OB-PREMISE ==== */
